summaryrefslogtreecommitdiff
path: root/boost/process/detail
diff options
context:
space:
mode:
Diffstat (limited to 'boost/process/detail')
-rw-r--r--boost/process/detail/async_handler.hpp117
-rw-r--r--boost/process/detail/basic_cmd.hpp292
-rw-r--r--boost/process/detail/child_decl.hpp243
-rw-r--r--boost/process/detail/config.hpp99
-rw-r--r--boost/process/detail/execute_impl.hpp284
-rw-r--r--boost/process/detail/handler.hpp75
-rw-r--r--boost/process/detail/handler_base.hpp49
-rw-r--r--boost/process/detail/on_exit.hpp53
-rw-r--r--boost/process/detail/posix/asio_fwd.hpp79
-rw-r--r--boost/process/detail/posix/async_handler.hpp40
-rw-r--r--boost/process/detail/posix/async_in.hpp95
-rw-r--r--boost/process/detail/posix/async_out.hpp170
-rw-r--r--boost/process/detail/posix/async_pipe.hpp355
-rw-r--r--boost/process/detail/posix/basic_cmd.hpp177
-rw-r--r--boost/process/detail/posix/basic_pipe.hpp193
-rw-r--r--boost/process/detail/posix/child_handle.hpp60
-rw-r--r--boost/process/detail/posix/close_in.hpp30
-rw-r--r--boost/process/detail/posix/close_out.hpp55
-rw-r--r--boost/process/detail/posix/cmd.hpp104
-rw-r--r--boost/process/detail/posix/compare_handles.hpp42
-rw-r--r--boost/process/detail/posix/env_init.hpp41
-rw-r--r--boost/process/detail/posix/environment.hpp322
-rw-r--r--boost/process/detail/posix/exe.hpp36
-rw-r--r--boost/process/detail/posix/executor.hpp547
-rw-r--r--boost/process/detail/posix/fd.hpp92
-rw-r--r--boost/process/detail/posix/file_descriptor.hpp76
-rw-r--r--boost/process/detail/posix/file_in.hpp40
-rw-r--r--boost/process/detail/posix/file_out.hpp65
-rw-r--r--boost/process/detail/posix/group_handle.hpp103
-rw-r--r--boost/process/detail/posix/group_ref.hpp52
-rw-r--r--boost/process/detail/posix/handler.hpp74
-rw-r--r--boost/process/detail/posix/io_service_ref.hpp155
-rw-r--r--boost/process/detail/posix/is_running.hpp78
-rw-r--r--boost/process/detail/posix/null_in.hpp35
-rw-r--r--boost/process/detail/posix/null_out.hpp58
-rw-r--r--boost/process/detail/posix/on_exit.hpp35
-rw-r--r--boost/process/detail/posix/pipe_in.hpp90
-rw-r--r--boost/process/detail/posix/pipe_out.hpp116
-rw-r--r--boost/process/detail/posix/search_path.hpp39
-rw-r--r--boost/process/detail/posix/shell_path.hpp32
-rw-r--r--boost/process/detail/posix/signal.hpp79
-rw-r--r--boost/process/detail/posix/start_dir.hpp38
-rw-r--r--boost/process/detail/posix/terminate.hpp44
-rw-r--r--boost/process/detail/posix/use_vfork.hpp33
-rw-r--r--boost/process/detail/posix/wait_for_exit.hpp205
-rw-r--r--boost/process/detail/posix/wait_group.hpp191
-rw-r--r--boost/process/detail/throw_on_error.hpp36
-rw-r--r--boost/process/detail/traits.hpp17
-rw-r--r--boost/process/detail/traits/async.hpp34
-rw-r--r--boost/process/detail/traits/cmd_or_exe.hpp85
-rw-r--r--boost/process/detail/traits/decl.hpp76
-rw-r--r--boost/process/detail/traits/env.hpp53
-rw-r--r--boost/process/detail/traits/error.hpp27
-rw-r--r--boost/process/detail/traits/group.hpp37
-rw-r--r--boost/process/detail/traits/wchar_t.hpp274
-rw-r--r--boost/process/detail/windows/asio_fwd.hpp71
-rw-r--r--boost/process/detail/windows/async_handler.hpp40
-rw-r--r--boost/process/detail/windows/async_in.hpp105
-rw-r--r--boost/process/detail/windows/async_out.hpp176
-rw-r--r--boost/process/detail/windows/async_pipe.hpp415
-rw-r--r--boost/process/detail/windows/basic_cmd.hpp164
-rw-r--r--boost/process/detail/windows/basic_pipe.hpp225
-rw-r--r--boost/process/detail/windows/child_handle.hpp98
-rw-r--r--boost/process/detail/windows/close_in.hpp31
-rw-r--r--boost/process/detail/windows/close_out.hpp53
-rw-r--r--boost/process/detail/windows/cmd.hpp49
-rw-r--r--boost/process/detail/windows/compare_handles.hpp41
-rw-r--r--boost/process/detail/windows/env_init.hpp54
-rw-r--r--boost/process/detail/windows/environment.hpp356
-rw-r--r--boost/process/detail/windows/executor.hpp259
-rw-r--r--boost/process/detail/windows/file_descriptor.hpp104
-rw-r--r--boost/process/detail/windows/file_in.hpp44
-rw-r--r--boost/process/detail/windows/file_out.hpp77
-rw-r--r--boost/process/detail/windows/group_handle.hpp191
-rw-r--r--boost/process/detail/windows/group_ref.hpp51
-rw-r--r--boost/process/detail/windows/handler.hpp20
-rw-r--r--boost/process/detail/windows/io_service_ref.hpp160
-rw-r--r--boost/process/detail/windows/is_running.hpp64
-rw-r--r--boost/process/detail/windows/job_workaround.hpp139
-rw-r--r--boost/process/detail/windows/locale.hpp103
-rw-r--r--boost/process/detail/windows/null_in.hpp41
-rw-r--r--boost/process/detail/windows/null_out.hpp75
-rw-r--r--boost/process/detail/windows/on_exit.hpp40
-rw-r--r--boost/process/detail/windows/pipe_in.hpp89
-rw-r--r--boost/process/detail/windows/pipe_out.hpp122
-rw-r--r--boost/process/detail/windows/search_path.hpp54
-rw-r--r--boost/process/detail/windows/shell_path.hpp53
-rw-r--r--boost/process/detail/windows/show_window.hpp39
-rw-r--r--boost/process/detail/windows/start_dir.hpp36
-rw-r--r--boost/process/detail/windows/terminate.hpp49
-rw-r--r--boost/process/detail/windows/wait_for_exit.hpp193
-rw-r--r--boost/process/detail/windows/wait_group.hpp121
92 files changed, 9929 insertions, 0 deletions
diff --git a/boost/process/detail/async_handler.hpp b/boost/process/detail/async_handler.hpp
new file mode 100644
index 0000000000..832a42014e
--- /dev/null
+++ b/boost/process/detail/async_handler.hpp
@@ -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_ */
diff --git a/boost/process/detail/basic_cmd.hpp b/boost/process/detail/basic_cmd.hpp
new file mode 100644
index 0000000000..e387d9f0c5
--- /dev/null
+++ b/boost/process/detail/basic_cmd.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_ */
diff --git a/boost/process/detail/child_decl.hpp b/boost/process/detail/child_decl.hpp
new file mode 100644
index 0000000000..3483f7c4b8
--- /dev/null
+++ b/boost/process/detail/child_decl.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
+
diff --git a/boost/process/detail/config.hpp b/boost/process/detail/config.hpp
new file mode 100644
index 0000000000..2e280c1d53
--- /dev/null
+++ b/boost/process/detail/config.hpp
@@ -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
diff --git a/boost/process/detail/execute_impl.hpp b/boost/process/detail/execute_impl.hpp
new file mode 100644
index 0000000000..77722f78ca
--- /dev/null
+++ b/boost/process/detail/execute_impl.hpp
@@ -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
diff --git a/boost/process/detail/handler.hpp b/boost/process/detail/handler.hpp
new file mode 100644
index 0000000000..360c59f81a
--- /dev/null
+++ b/boost/process/detail/handler.hpp
@@ -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_ */
diff --git a/boost/process/detail/handler_base.hpp b/boost/process/detail/handler_base.hpp
new file mode 100644
index 0000000000..93a80520ee
--- /dev/null
+++ b/boost/process/detail/handler_base.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
diff --git a/boost/process/detail/on_exit.hpp b/boost/process/detail/on_exit.hpp
new file mode 100644
index 0000000000..d0fd5b8c84
--- /dev/null
+++ b/boost/process/detail/on_exit.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_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_ */
diff --git a/boost/process/detail/posix/asio_fwd.hpp b/boost/process/detail/posix/asio_fwd.hpp
new file mode 100644
index 0000000000..06d5c19214
--- /dev/null
+++ b/boost/process/detail/posix/asio_fwd.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_ */
diff --git a/boost/process/detail/posix/async_handler.hpp b/boost/process/detail/posix/async_handler.hpp
new file mode 100644
index 0000000000..a61cff3372
--- /dev/null
+++ b/boost/process/detail/posix/async_handler.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_ */
diff --git a/boost/process/detail/posix/async_in.hpp b/boost/process/detail/posix/async_in.hpp
new file mode 100644
index 0000000000..9814c593f2
--- /dev/null
+++ b/boost/process/detail/posix/async_in.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
diff --git a/boost/process/detail/posix/async_out.hpp b/boost/process/detail/posix/async_out.hpp
new file mode 100644
index 0000000000..b0f7876714
--- /dev/null
+++ b/boost/process/detail/posix/async_out.hpp
@@ -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
diff --git a/boost/process/detail/posix/async_pipe.hpp b/boost/process/detail/posix/async_pipe.hpp
new file mode 100644
index 0000000000..d849559c20
--- /dev/null
+++ b/boost/process/detail/posix/async_pipe.hpp
@@ -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_ */
diff --git a/boost/process/detail/posix/basic_cmd.hpp b/boost/process/detail/posix/basic_cmd.hpp
new file mode 100644
index 0000000000..eefcc5c53f
--- /dev/null
+++ b/boost/process/detail/posix/basic_cmd.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
diff --git a/boost/process/detail/posix/basic_pipe.hpp b/boost/process/detail/posix/basic_pipe.hpp
new file mode 100644
index 0000000000..77fc90a4c1
--- /dev/null
+++ b/boost/process/detail/posix/basic_pipe.hpp
@@ -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
diff --git a/boost/process/detail/posix/child_handle.hpp b/boost/process/detail/posix/child_handle.hpp
new file mode 100644
index 0000000000..44ec43ea68
--- /dev/null
+++ b/boost/process/detail/posix/child_handle.hpp
@@ -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
diff --git a/boost/process/detail/posix/close_in.hpp b/boost/process/detail/posix/close_in.hpp
new file mode 100644
index 0000000000..74cffd6729
--- /dev/null
+++ b/boost/process/detail/posix/close_in.hpp
@@ -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
diff --git a/boost/process/detail/posix/close_out.hpp b/boost/process/detail/posix/close_out.hpp
new file mode 100644
index 0000000000..f3659f5544
--- /dev/null
+++ b/boost/process/detail/posix/close_out.hpp
@@ -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
diff --git a/boost/process/detail/posix/cmd.hpp b/boost/process/detail/posix/cmd.hpp
new file mode 100644
index 0000000000..ab4f4fb066
--- /dev/null
+++ b/boost/process/detail/posix/cmd.hpp
@@ -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
diff --git a/boost/process/detail/posix/compare_handles.hpp b/boost/process/detail/posix/compare_handles.hpp
new file mode 100644
index 0000000000..634757215f
--- /dev/null
+++ b/boost/process/detail/posix/compare_handles.hpp
@@ -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_ */
diff --git a/boost/process/detail/posix/env_init.hpp b/boost/process/detail/posix/env_init.hpp
new file mode 100644
index 0000000000..4d01cdad11
--- /dev/null
+++ b/boost/process/detail/posix/env_init.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_ */
diff --git a/boost/process/detail/posix/environment.hpp b/boost/process/detail/posix/environment.hpp
new file mode 100644
index 0000000000..1011c03a9d
--- /dev/null
+++ b/boost/process/detail/posix/environment.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_ */
diff --git a/boost/process/detail/posix/exe.hpp b/boost/process/detail/posix/exe.hpp
new file mode 100644
index 0000000000..9de68acc4e
--- /dev/null
+++ b/boost/process/detail/posix/exe.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_ */
diff --git a/boost/process/detail/posix/executor.hpp b/boost/process/detail/posix/executor.hpp
new file mode 100644
index 0000000000..5d03fd184e
--- /dev/null
+++ b/boost/process/detail/posix/executor.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
diff --git a/boost/process/detail/posix/fd.hpp b/boost/process/detail/posix/fd.hpp
new file mode 100644
index 0000000000..51790c3237
--- /dev/null
+++ b/boost/process/detail/posix/fd.hpp
@@ -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
diff --git a/boost/process/detail/posix/file_descriptor.hpp b/boost/process/detail/posix/file_descriptor.hpp
new file mode 100644
index 0000000000..72552444b0
--- /dev/null
+++ b/boost/process/detail/posix/file_descriptor.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_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_ */
diff --git a/boost/process/detail/posix/file_in.hpp b/boost/process/detail/posix/file_in.hpp
new file mode 100644
index 0000000000..c3ceeeead2
--- /dev/null
+++ b/boost/process/detail/posix/file_in.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
diff --git a/boost/process/detail/posix/file_out.hpp b/boost/process/detail/posix/file_out.hpp
new file mode 100644
index 0000000000..6fef732598
--- /dev/null
+++ b/boost/process/detail/posix/file_out.hpp
@@ -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
diff --git a/boost/process/detail/posix/group_handle.hpp b/boost/process/detail/posix/group_handle.hpp
new file mode 100644
index 0000000000..856b36a6b0
--- /dev/null
+++ b/boost/process/detail/posix/group_handle.hpp
@@ -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_ */
diff --git a/boost/process/detail/posix/group_ref.hpp b/boost/process/detail/posix/group_ref.hpp
new file mode 100644
index 0000000000..d46e631fe7
--- /dev/null
+++ b/boost/process/detail/posix/group_ref.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_ */
diff --git a/boost/process/detail/posix/handler.hpp b/boost/process/detail/posix/handler.hpp
new file mode 100644
index 0000000000..506db4e649
--- /dev/null
+++ b/boost/process/detail/posix/handler.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_ */
diff --git a/boost/process/detail/posix/io_service_ref.hpp b/boost/process/detail/posix/io_service_ref.hpp
new file mode 100644
index 0000000000..ced1d51033
--- /dev/null
+++ b/boost/process/detail/posix/io_service_ref.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_ */
diff --git a/boost/process/detail/posix/is_running.hpp b/boost/process/detail/posix/is_running.hpp
new file mode 100644
index 0000000000..e8a009dd22
--- /dev/null
+++ b/boost/process/detail/posix/is_running.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
diff --git a/boost/process/detail/posix/null_in.hpp b/boost/process/detail/posix/null_in.hpp
new file mode 100644
index 0000000000..9f082054c6
--- /dev/null
+++ b/boost/process/detail/posix/null_in.hpp
@@ -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
diff --git a/boost/process/detail/posix/null_out.hpp b/boost/process/detail/posix/null_out.hpp
new file mode 100644
index 0000000000..ed4f915f35
--- /dev/null
+++ b/boost/process/detail/posix/null_out.hpp
@@ -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
diff --git a/boost/process/detail/posix/on_exit.hpp b/boost/process/detail/posix/on_exit.hpp
new file mode 100644
index 0000000000..d3160aff32
--- /dev/null
+++ b/boost/process/detail/posix/on_exit.hpp
@@ -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_ */
diff --git a/boost/process/detail/posix/pipe_in.hpp b/boost/process/detail/posix/pipe_in.hpp
new file mode 100644
index 0000000000..fa294cf310
--- /dev/null
+++ b/boost/process/detail/posix/pipe_in.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
diff --git a/boost/process/detail/posix/pipe_out.hpp b/boost/process/detail/posix/pipe_out.hpp
new file mode 100644
index 0000000000..0148c19d26
--- /dev/null
+++ b/boost/process/detail/posix/pipe_out.hpp
@@ -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
diff --git a/boost/process/detail/posix/search_path.hpp b/boost/process/detail/posix/search_path.hpp
new file mode 100644
index 0000000000..1ce5c65575
--- /dev/null
+++ b/boost/process/detail/posix/search_path.hpp
@@ -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
diff --git a/boost/process/detail/posix/shell_path.hpp b/boost/process/detail/posix/shell_path.hpp
new file mode 100644
index 0000000000..870cab6b90
--- /dev/null
+++ b/boost/process/detail/posix/shell_path.hpp
@@ -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
diff --git a/boost/process/detail/posix/signal.hpp b/boost/process/detail/posix/signal.hpp
new file mode 100644
index 0000000000..f9ef32d05d
--- /dev/null
+++ b/boost/process/detail/posix/signal.hpp
@@ -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
diff --git a/boost/process/detail/posix/start_dir.hpp b/boost/process/detail/posix/start_dir.hpp
new file mode 100644
index 0000000000..1b73172c8b
--- /dev/null
+++ b/boost/process/detail/posix/start_dir.hpp
@@ -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
diff --git a/boost/process/detail/posix/terminate.hpp b/boost/process/detail/posix/terminate.hpp
new file mode 100644
index 0000000000..d8048362b0
--- /dev/null
+++ b/boost/process/detail/posix/terminate.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_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
diff --git a/boost/process/detail/posix/use_vfork.hpp b/boost/process/detail/posix/use_vfork.hpp
new file mode 100644
index 0000000000..98f74b24ff
--- /dev/null
+++ b/boost/process/detail/posix/use_vfork.hpp
@@ -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_ */
diff --git a/boost/process/detail/posix/wait_for_exit.hpp b/boost/process/detail/posix/wait_for_exit.hpp
new file mode 100644
index 0000000000..bf25e2a3d8
--- /dev/null
+++ b/boost/process/detail/posix/wait_for_exit.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
diff --git a/boost/process/detail/posix/wait_group.hpp b/boost/process/detail/posix/wait_group.hpp
new file mode 100644
index 0000000000..8b768ffc14
--- /dev/null
+++ b/boost/process/detail/posix/wait_group.hpp
@@ -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
diff --git a/boost/process/detail/throw_on_error.hpp b/boost/process/detail/throw_on_error.hpp
new file mode 100644
index 0000000000..071aaec0cf
--- /dev/null
+++ b/boost/process/detail/throw_on_error.hpp
@@ -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
diff --git a/boost/process/detail/traits.hpp b/boost/process/detail/traits.hpp
new file mode 100644
index 0000000000..a1b0e6b19b
--- /dev/null
+++ b/boost/process/detail/traits.hpp
@@ -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_ */
diff --git a/boost/process/detail/traits/async.hpp b/boost/process/detail/traits/async.hpp
new file mode 100644
index 0000000000..da7ed79aae
--- /dev/null
+++ b/boost/process/detail/traits/async.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_ */
diff --git a/boost/process/detail/traits/cmd_or_exe.hpp b/boost/process/detail/traits/cmd_or_exe.hpp
new file mode 100644
index 0000000000..f6a8ae7cd3
--- /dev/null
+++ b/boost/process/detail/traits/cmd_or_exe.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_ */
diff --git a/boost/process/detail/traits/decl.hpp b/boost/process/detail/traits/decl.hpp
new file mode 100644
index 0000000000..48f8022f73
--- /dev/null
+++ b/boost/process/detail/traits/decl.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_ */
diff --git a/boost/process/detail/traits/env.hpp b/boost/process/detail/traits/env.hpp
new file mode 100644
index 0000000000..ccdcad046a
--- /dev/null
+++ b/boost/process/detail/traits/env.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_ */
diff --git a/boost/process/detail/traits/error.hpp b/boost/process/detail/traits/error.hpp
new file mode 100644
index 0000000000..2d1912bda9
--- /dev/null
+++ b/boost/process/detail/traits/error.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_ */
diff --git a/boost/process/detail/traits/group.hpp b/boost/process/detail/traits/group.hpp
new file mode 100644
index 0000000000..3e7897c689
--- /dev/null
+++ b/boost/process/detail/traits/group.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_ */
diff --git a/boost/process/detail/traits/wchar_t.hpp b/boost/process/detail/traits/wchar_t.hpp
new file mode 100644
index 0000000000..812a92cf13
--- /dev/null
+++ b/boost/process/detail/traits/wchar_t.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_ */
diff --git a/boost/process/detail/windows/asio_fwd.hpp b/boost/process/detail/windows/asio_fwd.hpp
new file mode 100644
index 0000000000..f7667db101
--- /dev/null
+++ b/boost/process/detail/windows/asio_fwd.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_ */
diff --git a/boost/process/detail/windows/async_handler.hpp b/boost/process/detail/windows/async_handler.hpp
new file mode 100644
index 0000000000..197c264126
--- /dev/null
+++ b/boost/process/detail/windows/async_handler.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_ */
diff --git a/boost/process/detail/windows/async_in.hpp b/boost/process/detail/windows/async_in.hpp
new file mode 100644
index 0000000000..4c498612d3
--- /dev/null
+++ b/boost/process/detail/windows/async_in.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
diff --git a/boost/process/detail/windows/async_out.hpp b/boost/process/detail/windows/async_out.hpp
new file mode 100644
index 0000000000..435f56ebd6
--- /dev/null
+++ b/boost/process/detail/windows/async_out.hpp
@@ -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
diff --git a/boost/process/detail/windows/async_pipe.hpp b/boost/process/detail/windows/async_pipe.hpp
new file mode 100644
index 0000000000..ca4f3559d0
--- /dev/null
+++ b/boost/process/detail/windows/async_pipe.hpp
@@ -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_ */
diff --git a/boost/process/detail/windows/basic_cmd.hpp b/boost/process/detail/windows/basic_cmd.hpp
new file mode 100644
index 0000000000..176a052368
--- /dev/null
+++ b/boost/process/detail/windows/basic_cmd.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_ */
diff --git a/boost/process/detail/windows/basic_pipe.hpp b/boost/process/detail/windows/basic_pipe.hpp
new file mode 100644
index 0000000000..2471e60f6d
--- /dev/null
+++ b/boost/process/detail/windows/basic_pipe.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
diff --git a/boost/process/detail/windows/child_handle.hpp b/boost/process/detail/windows/child_handle.hpp
new file mode 100644
index 0000000000..4e809be9fc
--- /dev/null
+++ b/boost/process/detail/windows/child_handle.hpp
@@ -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
diff --git a/boost/process/detail/windows/close_in.hpp b/boost/process/detail/windows/close_in.hpp
new file mode 100644
index 0000000000..5100564b4c
--- /dev/null
+++ b/boost/process/detail/windows/close_in.hpp
@@ -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
diff --git a/boost/process/detail/windows/close_out.hpp b/boost/process/detail/windows/close_out.hpp
new file mode 100644
index 0000000000..dc3de412fc
--- /dev/null
+++ b/boost/process/detail/windows/close_out.hpp
@@ -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
diff --git a/boost/process/detail/windows/cmd.hpp b/boost/process/detail/windows/cmd.hpp
new file mode 100644
index 0000000000..c76c08a546
--- /dev/null
+++ b/boost/process/detail/windows/cmd.hpp
@@ -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_ */
diff --git a/boost/process/detail/windows/compare_handles.hpp b/boost/process/detail/windows/compare_handles.hpp
new file mode 100644
index 0000000000..1eafd43209
--- /dev/null
+++ b/boost/process/detail/windows/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_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_ */
diff --git a/boost/process/detail/windows/env_init.hpp b/boost/process/detail/windows/env_init.hpp
new file mode 100644
index 0000000000..036a29809f
--- /dev/null
+++ b/boost/process/detail/windows/env_init.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_ */
diff --git a/boost/process/detail/windows/environment.hpp b/boost/process/detail/windows/environment.hpp
new file mode 100644
index 0000000000..b73da1bd42
--- /dev/null
+++ b/boost/process/detail/windows/environment.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_ */
diff --git a/boost/process/detail/windows/executor.hpp b/boost/process/detail/windows/executor.hpp
new file mode 100644
index 0000000000..30b1e46369
--- /dev/null
+++ b/boost/process/detail/windows/executor.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
diff --git a/boost/process/detail/windows/file_descriptor.hpp b/boost/process/detail/windows/file_descriptor.hpp
new file mode 100644
index 0000000000..337e634781
--- /dev/null
+++ b/boost/process/detail/windows/file_descriptor.hpp
@@ -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_ */
diff --git a/boost/process/detail/windows/file_in.hpp b/boost/process/detail/windows/file_in.hpp
new file mode 100644
index 0000000000..b092d278c2
--- /dev/null
+++ b/boost/process/detail/windows/file_in.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
diff --git a/boost/process/detail/windows/file_out.hpp b/boost/process/detail/windows/file_out.hpp
new file mode 100644
index 0000000000..2e2cc198cf
--- /dev/null
+++ b/boost/process/detail/windows/file_out.hpp
@@ -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
diff --git a/boost/process/detail/windows/group_handle.hpp b/boost/process/detail/windows/group_handle.hpp
new file mode 100644
index 0000000000..e289263cad
--- /dev/null
+++ b/boost/process/detail/windows/group_handle.hpp
@@ -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_ */
diff --git a/boost/process/detail/windows/group_ref.hpp b/boost/process/detail/windows/group_ref.hpp
new file mode 100644
index 0000000000..1f62c4dcb0
--- /dev/null
+++ b/boost/process/detail/windows/group_ref.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_ */
diff --git a/boost/process/detail/windows/handler.hpp b/boost/process/detail/windows/handler.hpp
new file mode 100644
index 0000000000..f8ef89f016
--- /dev/null
+++ b/boost/process/detail/windows/handler.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_ */
diff --git a/boost/process/detail/windows/io_service_ref.hpp b/boost/process/detail/windows/io_service_ref.hpp
new file mode 100644
index 0000000000..6b61c7ca2c
--- /dev/null
+++ b/boost/process/detail/windows/io_service_ref.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_ */
diff --git a/boost/process/detail/windows/is_running.hpp b/boost/process/detail/windows/is_running.hpp
new file mode 100644
index 0000000000..66cc6837ae
--- /dev/null
+++ b/boost/process/detail/windows/is_running.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
diff --git a/boost/process/detail/windows/job_workaround.hpp b/boost/process/detail/windows/job_workaround.hpp
new file mode 100644
index 0000000000..b915d0c088
--- /dev/null
+++ b/boost/process/detail/windows/job_workaround.hpp
@@ -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_ */
diff --git a/boost/process/detail/windows/locale.hpp b/boost/process/detail/windows/locale.hpp
new file mode 100644
index 0000000000..34da2a69d3
--- /dev/null
+++ b/boost/process/detail/windows/locale.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_ */
diff --git a/boost/process/detail/windows/null_in.hpp b/boost/process/detail/windows/null_in.hpp
new file mode 100644
index 0000000000..f5c0ae6bf7
--- /dev/null
+++ b/boost/process/detail/windows/null_in.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
diff --git a/boost/process/detail/windows/null_out.hpp b/boost/process/detail/windows/null_out.hpp
new file mode 100644
index 0000000000..1bc19586c1
--- /dev/null
+++ b/boost/process/detail/windows/null_out.hpp
@@ -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
diff --git a/boost/process/detail/windows/on_exit.hpp b/boost/process/detail/windows/on_exit.hpp
new file mode 100644
index 0000000000..751f6a5f85
--- /dev/null
+++ b/boost/process/detail/windows/on_exit.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_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_ */
diff --git a/boost/process/detail/windows/pipe_in.hpp b/boost/process/detail/windows/pipe_in.hpp
new file mode 100644
index 0000000000..cd8c186e15
--- /dev/null
+++ b/boost/process/detail/windows/pipe_in.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
diff --git a/boost/process/detail/windows/pipe_out.hpp b/boost/process/detail/windows/pipe_out.hpp
new file mode 100644
index 0000000000..c32f0a604e
--- /dev/null
+++ b/boost/process/detail/windows/pipe_out.hpp
@@ -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
diff --git a/boost/process/detail/windows/search_path.hpp b/boost/process/detail/windows/search_path.hpp
new file mode 100644
index 0000000000..53fb966784
--- /dev/null
+++ b/boost/process/detail/windows/search_path.hpp
@@ -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
diff --git a/boost/process/detail/windows/shell_path.hpp b/boost/process/detail/windows/shell_path.hpp
new file mode 100644
index 0000000000..7cce445292
--- /dev/null
+++ b/boost/process/detail/windows/shell_path.hpp
@@ -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
diff --git a/boost/process/detail/windows/show_window.hpp b/boost/process/detail/windows/show_window.hpp
new file mode 100644
index 0000000000..ed42ebc56e
--- /dev/null
+++ b/boost/process/detail/windows/show_window.hpp
@@ -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
+
diff --git a/boost/process/detail/windows/start_dir.hpp b/boost/process/detail/windows/start_dir.hpp
new file mode 100644
index 0000000000..06629ed1f8
--- /dev/null
+++ b/boost/process/detail/windows/start_dir.hpp
@@ -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
diff --git a/boost/process/detail/windows/terminate.hpp b/boost/process/detail/windows/terminate.hpp
new file mode 100644
index 0000000000..a10b074078
--- /dev/null
+++ b/boost/process/detail/windows/terminate.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
+//
+// 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
diff --git a/boost/process/detail/windows/wait_for_exit.hpp b/boost/process/detail/windows/wait_for_exit.hpp
new file mode 100644
index 0000000000..decdb51172
--- /dev/null
+++ b/boost/process/detail/windows/wait_for_exit.hpp
@@ -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
diff --git a/boost/process/detail/windows/wait_group.hpp b/boost/process/detail/windows/wait_group.hpp
new file mode 100644
index 0000000000..449985f2fc
--- /dev/null
+++ b/boost/process/detail/windows/wait_group.hpp
@@ -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_ */