diff options
Diffstat (limited to 'boost/process')
115 files changed, 14935 insertions, 0 deletions
diff --git a/boost/process/args.hpp b/boost/process/args.hpp new file mode 100644 index 0000000000..af677cfd82 --- /dev/null +++ b/boost/process/args.hpp @@ -0,0 +1,279 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PROCESS_ARGS_HPP +#define BOOST_PROCESS_ARGS_HPP + +/** \file boost/process/args.hpp + * + * This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the + * alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly . + * + * +\xmlonly +<programlisting> +namespace boost { + namespace process { + <emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>; + } +} +</programlisting> +\endxmlonly + */ + + +#include <boost/process/detail/basic_cmd.hpp> +#include <iterator> + +namespace boost { namespace process { namespace detail { + +struct args_ +{ + template<typename T> + using remove_reference_t = typename std::remove_reference<T>::type; + template<typename T> + using value_type = typename remove_reference_t<T>::value_type; + + template<typename T> + using vvalue_type = value_type<value_type<T>>; + + template <class Range> + arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const + { + return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range)); + } + template <class Range> + arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const + { + return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range)); + } + template <class Range> + arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const + { + return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range)); + } + template<typename Char> + arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const + { + return arg_setter_<Char, false>(str); + } + template<typename Char> + arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const + { + return arg_setter_<Char, false>(str); + } + template<typename Char> + arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const + { + return arg_setter_<Char, false>(str); + } + template<typename Char> + arg_setter_<Char, true> operator()(const Char* str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, true> operator+=(const Char* str) const + { + return arg_setter_<Char, true> (str); + } + template<typename Char> + arg_setter_<Char, false> operator= (const Char* str) const + { + return arg_setter_<Char, false>(str); + } +// template<typename Char, std::size_t Size> +// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const +// { +// return arg_setter_<Char, true> (str); +// } +// template<typename Char, std::size_t Size> +// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const +// { +// return arg_setter_<Char, true> (str); +// } +// template<typename Char, std::size_t Size> +// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const +// { +// return arg_setter_<Char, false>(str); +// } + + arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const + { + return arg_setter_<char>(range.begin(), range.end()); + } + arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const + { + return arg_setter_<char, true>(range.begin(), range.end()); + } + arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const + { + return arg_setter_<char, true>(range.begin(), range.end()); + } + arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const + { + return arg_setter_<char>(range.begin(), range.end()); + } + arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const + { + return arg_setter_<char, true>(range.begin(), range.end()); + } + arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const + { + return arg_setter_<char, true>(range.begin(), range.end()); + } + + arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const + { + return arg_setter_<wchar_t>(range.begin(), range.end()); + } + arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const + { + return arg_setter_<wchar_t, true>(range.begin(), range.end()); + } + arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const + { + return arg_setter_<wchar_t, true>(range.begin(), range.end()); + } + arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const + { + return arg_setter_<wchar_t>(range.begin(), range.end()); + } + arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const + { + return arg_setter_<wchar_t, true>(range.begin(), range.end()); + } + arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const + { + return arg_setter_<wchar_t, true>(range.begin(), range.end()); + } +}; + + +} +/** + +The `args` property allows to explicitly set arguments for the execution. The +name of the executable will always be the first element in the arg-vector. + +\section args_details Details + +\subsection args_operations Operations + +\subsubsection args_set_var Setting values + +To set a the argument vector the following syntax can be used. + +\code{.cpp} +args = value; +args(value); +\endcode + +`std::initializer_list` is among the allowed types, so the following syntax is also possible. + +\code{.cpp} +args = {value1, value2}; +args({value1, value2}); +\endcode + +Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`. + +\paragraph args_set_var_value value + + - `std::basic_string<char_type>` + - `const char_type * ` + - `std::initializer_list<const char_type *>` + - `std::vector<std::basic_string<char_type>>` + +Additionally any range of `std::basic_string<char_type>` can be passed. + +\subsubsection args_append_var Appending values + +To append a the argument vector the following syntax can be used. + +\code{.cpp} +args += value; +\endcode + +`std::initializer_list` is among the allowed types, so the following syntax is also possible. + +\code{.cpp} +args += {value1, value2}; +\endcode + +Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`. + +\paragraph args_append_var_value value + + - `std::basic_string<char_type>` + - `const char_type * ` + - `std::initializer_list<const char_type *>` + - `std::vector<std::basic_string<char_type>>` + +Additionally any range of `std::basic_string<char_type>` can be passed. + + +\subsection args_example Example + +The overload form is used when more than one string is passed, from the second one forward. +I.e. the following expressions have the same results: + +\code{.cpp} +spawn("gcc", "--version"); +spawn("gcc", args ="--version"); +spawn("gcc", args+="--version"); +spawn("gcc", args ={"--version"}); +spawn("gcc", args+={"--version"}); +\endcode + +\note A string will be parsed and set in quotes if it has none and contains spaces. + + + */ +constexpr boost::process::detail::args_ args{}; + +///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly . +constexpr boost::process::detail::args_ argv{}; + + +}} + +#endif diff --git a/boost/process/async.hpp b/boost/process/async.hpp new file mode 100644 index 0000000000..9698aab931 --- /dev/null +++ b/boost/process/async.hpp @@ -0,0 +1,130 @@ +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** \file boost/process/async.hpp + +The header which provides the basic asynchrounous features. +It provides the on_exit property, which allows callbacks when the process exits. +It also implements the necessary traits for passing an boost::asio::io_service, +which is needed for asynchronous communication. + +It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html) +into the boost::process namespace for convenience. + +\xmlonly +<programlisting> +namespace boost { + namespace process { + <emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>; + } +} +</programlisting> + +\endxmlonly + */ + +#ifndef BOOST_PROCESS_ASYNC_HPP_ +#define BOOST_PROCESS_ASYNC_HPP_ + +#include <boost/process/detail/traits.hpp> +#include <boost/process/detail/on_exit.hpp> + +#include <boost/asio/io_service.hpp> +#include <boost/asio/streambuf.hpp> +#include <boost/asio/buffer.hpp> +#include <type_traits> +#include <boost/fusion/iterator/deref.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/io_service_ref.hpp> +#include <boost/process/detail/posix/async_in.hpp> +#include <boost/process/detail/posix/async_out.hpp> +#include <boost/process/detail/posix/on_exit.hpp> + +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/io_service_ref.hpp> +#include <boost/process/detail/windows/async_in.hpp> +#include <boost/process/detail/windows/async_out.hpp> +#include <boost/process/detail/windows/on_exit.hpp> +#endif + +namespace boost { namespace process { namespace detail { + +struct async_tag; + +template<typename T> +struct is_io_service : std::false_type {}; +template<> +struct is_io_service<api::io_service_ref> : std::true_type {}; + +template<typename Tuple> +inline asio::io_service& get_io_service(const Tuple & tup) +{ + auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup); + return ref.get(); +} + +struct async_builder +{ + boost::asio::io_service * ios; + + void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;}; + + typedef api::io_service_ref result_type; + api::io_service_ref get_initializer() {return api::io_service_ref (*ios);}; +}; + + +template<> +struct initializer_builder<async_tag> +{ + typedef async_builder type; +}; + +} + +using ::boost::asio::buffer; + + +#if defined(BOOST_PROCESS_DOXYGEN) +/** When an io_service is passed, the on_exit property can be used, to be notified + when the child process exits. + + +The following syntax is valid + +\code{.cpp} +on_exit=function; +on_exit(function); +\endcode + +with `function` being a callable object with the signature `(int, const std::error_code&)` or an +`std::future<int>`. + +\par Example + +\code{.cpp} +io_service ios; + +child c("ls", on_exit=[](int exit, const std::error_code& ec_in){}); + +std::future<int> exit_code; +chlid c2("ls", on_exit=exit_code); + +\endcode + +\note The handler is not invoked when the launch fails. +\warning When used \ref ignore_error it might gte invoked on error. + + */ +constexpr static ::boost::process::detail::on_exit_ on_exit{}; +#endif + +}} + + + +#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */ diff --git a/boost/process/async_pipe.hpp b/boost/process/async_pipe.hpp new file mode 100644 index 0000000000..97af165859 --- /dev/null +++ b/boost/process/async_pipe.hpp @@ -0,0 +1,215 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_PROCESS_ASYNC_PIPE_HPP +#define BOOST_PROCESS_ASYNC_PIPE_HPP + +#include <boost/config.hpp> +#include <boost/process/detail/config.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/async_pipe.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/async_pipe.hpp> +#endif + +namespace boost { namespace process { + + +#if defined(BOOST_PROCESS_DOXYGEN) + + +/** Class implementing and asnychronous I/O-Object for use with boost.asio. + * It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or + * boost::asio::posix::stream_descriptor. + * + * It can be used directly with boost::asio::async_read or async_write. + * + * \note The object is copyable, but that does invoke a handle duplicate. + */ +class async_pipe +{ +public: + /** Typedef for the native handle representation. + * \note This is the handle on the system, not the boost.asio class. + * + */ + typedef platform_specific native_handle_type; + /** Typedef for the handle representation of boost.asio. + * + */ + typedef platform_specific handle_type; + + /** Construct a new async_pipe, does automatically open the pipe. + * Initializes source and sink with the same io_service. + * @note Windows creates a named pipe here, where the name is automatically generated. + */ + inline async_pipe(boost::asio::io_service & ios); + + /** Construct a new async_pipe, does automatically open the pipe. + * @note Windows creates a named pipe here, where the name is automatically generated. + */ + inline async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & ios_sink); + + /** Construct a new async_pipe, does automatically open. + * Initializes source and sink with the same io_service. + * + * @note Windows restricts possible names. + */ + inline async_pipe(boost::asio::io_service & ios, const std::string & name); + + + /** Construct a new async_pipe, does automatically open. + * + * @note Windows restricts possible names. + */ + inline async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & ios_sink, const std::string & name); + + /** Copy-Constructor of the async pipe. + * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. + * + */ + async_pipe(const async_pipe& lhs); + + /** Move-Constructor of the async pipe. + */ + async_pipe(async_pipe&& lhs); + + /** Construct the async-pipe from a pipe. + * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. + * + */ + template<class CharT, class Traits = std::char_traits<CharT>> + explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p); + + /** Construct the async-pipe from a pipe, with two different io_service objects. + * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. + * + */ + template<class CharT, class Traits = std::char_traits<CharT>> + explicit async_pipe(boost::asio::io_service & ios_source, + boost::asio::io_service & ios_sink, + const basic_pipe<CharT, Traits> & p); + + + /** Assign a basic_pipe. + * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. + * + */ + template<class CharT, class Traits = std::char_traits<CharT>> + inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p); + + /** Copy Assign a pipe. + * @note Duplicates the handles. + */ + async_pipe& operator=(const async_pipe& lhs); + /** Move assign a pipe */ + async_pipe& operator=(async_pipe&& lhs); + + /** Destructor. Closes the pipe handles. */ + ~async_pipe(); + + /** Explicit cast to basic_pipe. */ + template<class CharT, class Traits = std::char_traits<CharT>> + inline explicit operator basic_pipe<CharT, Traits>() const; + + /** Cancel the current asynchronous operations. */ + void cancel(); + /** Close the pipe handles. */ + void close(); + /** Close the pipe handles. While passing an error_code + * + */ + void close(std::error_code & ec); + + /** Check if the pipes are open. */ + bool is_open() const; + + /** Async close, i.e. close after current operation is completed. + * + * \note There is no guarantee that this will indeed read the entire pipe-buffer + */ + void async_close(); + + /** Read some data from the handle. + + * See the boost.asio documentation for more details. + */ + template<typename MutableBufferSequence> + std::size_t read_some(const MutableBufferSequence & buffers); + + /** Write some data to the handle. + + * See the boost.asio documentation for more details. + */ + template<typename MutableBufferSequence> + std::size_t write_some(const MutableBufferSequence & buffers); + + /** Get the native handle of the source. */ + native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();} + /** Get the native handle of the sink. */ + native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();} + + /** Start an asynchronous read. + * + * See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details. + */ + template<typename MutableBufferSequence, + typename ReadHandler> + detail::dummy async_read_some( + const MutableBufferSequence & buffers, + ReadHandler &&handler); + + /** Start an asynchronous write. + + * See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details. + */ + template<typename ConstBufferSequence, + typename WriteHandler> + detail::dummy async_write_some( + const ConstBufferSequence & buffers, + WriteHandler && handler); + + ///Get the asio handle of the pipe sink. + const handle_type & sink () const &; + ///Get the asio handle of the pipe source. + const handle_type & source() const &; + + ///Get the asio handle of the pipe sink. Qualified as rvalue + handle_type && sink () &&; + ///Get the asio handle of the pipe source. Qualified as rvalue + handle_type && source() &&; + + /// Move the source out of this class and change the io_service. Qualified as rvalue. \attention Will always move. + handle_type source(::boost::asio::io_service& ios) &&; + /// Move the sink out of this class and change the io_service. Qualified as rvalue. \attention Will always move + handle_type sink (::boost::asio::io_service& ios) &&; + + /// Copy the source out of this class and change the io_service. \attention Will always copy. + handle_type source(::boost::asio::io_service& ios) const &; + /// Copy the sink out of this class and change the io_service. \attention Will always copy + handle_type sink (::boost::asio::io_service& ios) const &; + + + +}; + +#else +using ::boost::process::detail::api::async_pipe; +#endif + + +}} + + + +#endif diff --git a/boost/process/async_system.hpp b/boost/process/async_system.hpp new file mode 100644 index 0000000000..f92b417d2e --- /dev/null +++ b/boost/process/async_system.hpp @@ -0,0 +1,142 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** + * \file boost/process/async_system.hpp + * + * Defines the asynchrounous version of the system function. + */ + +#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP +#define BOOST_PROCESS_ASYNC_SYSTEM_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/async.hpp> +#include <boost/process/child.hpp> +#include <boost/process/detail/async_handler.hpp> +#include <boost/process/detail/execute_impl.hpp> +#include <type_traits> +#include <memory> +#include <boost/asio/async_result.hpp> +#include <boost/system/error_code.hpp> +#include <tuple> + +#if defined(BOOST_POSIX_API) +#include <boost/process/posix.hpp> +#endif + +namespace boost { +namespace process { +namespace detail +{ + +template<typename ExitHandler> +struct async_system_handler : ::boost::process::detail::api::async_handler +{ + boost::asio::io_service & ios; + boost::asio::detail::async_result_init< + ExitHandler, void(boost::system::error_code, int)> init; + +#if defined(BOOST_POSIX_API) + bool errored = false; +#endif + + template<typename ExitHandler_> + async_system_handler( + boost::asio::io_service & ios, + ExitHandler_ && exit_handler) : ios(ios), init(std::forward<ExitHandler_>(exit_handler)) + { + + } + + + template<typename Exec> + void on_error(Exec&, const std::error_code & ec) + { +#if defined(BOOST_POSIX_API) + errored = true; +#endif + auto & h = init.handler; + ios.post( + [h, ec]() mutable + { + h(boost::system::error_code(ec.value(), boost::system::system_category()), -1); + }); + } + + BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) + get_result() + { + return init.result.get(); + } + + template<typename Executor> + std::function<void(int, const std::error_code&)> on_exit_handler(Executor&) + { +#if defined(BOOST_POSIX_API) + if (errored) + return [](int exit_code, const std::error_code & ec){}; +#endif + auto & h = init.handler; + return [h](int exit_code, const std::error_code & ec) mutable + { + h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code); + }; + } +}; + + +template<typename ExitHandler> +struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {}; + +} + +/** This function provides an asynchronous interface to process launching. + +It uses the same properties and parameters as the other launching function, +but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html) + +It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine +the return value (from the second parameter, `exit_handler`). + +\param ios A reference to an [io_service](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html) +\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)` + +\note This function does not allow custom error handling, since those are done through the `exit_handler`. + +*/ +#if defined(BOOST_PROCESS_DOXYGEN) +template<typename ExitHandler, typename ...Args> +inline boost::process::detail::dummy + async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args); +#endif + +template<typename ExitHandler, typename ...Args> +inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) + async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args) +{ + detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)}; + + typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type + has_err_handling; + + static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); + + + child(ios, std::forward<Args>(args)..., async_h ).detach(); + + return async_h.get_result(); +} + + + +}} +#endif + diff --git a/boost/process/child.hpp b/boost/process/child.hpp new file mode 100644 index 0000000000..980cecdae7 --- /dev/null +++ b/boost/process/child.hpp @@ -0,0 +1,147 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** + * \file boost/process/child.hpp + * + * Defines a child process class. + */ + +#ifndef BOOST_PROCESS_CHILD_HPP +#define BOOST_PROCESS_CHILD_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/child_decl.hpp> +#include <boost/process/detail/execute_impl.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/posix.hpp> +#endif + +namespace boost { + +///The main namespace of boost.process. +namespace process { + +template<typename ...Args> +child::child(Args&&...args) + : child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {} + + +#if defined(BOOST_PROCESS_DOXYGEN) +/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread), + * in that it has a join and detach function. + * + * @attention The destructor will call terminate on the process if not joined or detached without any warning. + * + */ + +class child +{ + /** Type definition for the native process handle. */ + typedef platform_specific native_handle_t; + + /** Construct the child from a pid. + * + * @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific. + */ + explicit child(pid_t & pid) : _child_handle(pid) {}; + + /** Move-Constructor.*/ + child(child && lhs); + + /** Construct a child from a property list and launch it + * The standard version is to create a subprocess, which will spawn the process. + */ + template<typename ...Args> + explicit child(Args&&...args); + + /** Construct an empty child. */ + child() = default; + + /** Move assign. */ + child& operator=(child && lhs); + + /** Detach the child, i.e. let it run after this handle dies. */ + void detach(); + /** Join the child. This just calls wait, but that way the naming is similar to std::thread */ + void join(); + /** Check if the child is joinable. */ + bool joinable(); + + /** Destructor. + * @attention Will call terminate (without warning) when the child was neither joined nor detached. + */ + ~child(); + + /** Get the native handle for the child process. */ + native_handle_t native_handle() const; + + /** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */ + int exit_code() const; + /** Get the Process Identifier. */ + pid_t id() const; + + /** Check if the child process is running. */ + bool running(); + /** \overload void running() */ + bool running(std::error_code & ec) noexcept; + + /** Wait for the child process to exit. */ + void wait(); + /** \overload void wait() */ + void wait(std::error_code & ec) noexcept; + + /** Wait for the child process to exit for a period of time. + * \return True if child exited while waiting. + */ + template< class Rep, class Period > + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time); + /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */ + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept; + + /** Wait for the child process to exit until a point in time. + * \return True if child exited while waiting.*/ + template< class Clock, class Duration > + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ); + /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/ + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept; + + /** Check if this handle holds a child process. + * @note That does not mean, that the process is still running. It only means, that the handle does or did exist. + */ + bool valid() const; + /** Same as valid, for convenience. */ + explicit operator bool() const; + + /** Check if the the chlid process is in any process group. */ + bool in_group() const; + + /** \overload bool in_group() const */ + bool in_group(std::error_code & ec) const noexcept; + + /** Terminate the child process. + * + * This function will cause the child process to unconditionally and immediately exit. + * It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix + * and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows. + * + */ + void terminate(); + + /** \overload void terminate() */ + void terminate(std::error_code & ec) noexcept; +}; + +#endif + +}} +#endif + diff --git a/boost/process/cmd.hpp b/boost/process/cmd.hpp new file mode 100644 index 0000000000..5985c81430 --- /dev/null +++ b/boost/process/cmd.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_DETAIL_CMD_LINE_HPP
+#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
+ +#include <boost/detail/winapi/config.hpp>
+#include <boost/process/detail/config.hpp>
+#include <boost/process/detail/handler_base.hpp>
+#include <boost/process/detail/traits/cmd_or_exe.hpp>
+#include <boost/process/detail/traits/wchar_t.hpp>
+ +#if defined(BOOST_POSIX_API)
+#include <boost/process/detail/posix/cmd.hpp>
+#elif defined(BOOST_WINDOWS_API)
+#include <boost/process/detail/windows/cmd.hpp>
+#endif
+ +/** \file boost/process/cmd.hpp
+ *
+ * This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
+ *
+\xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
+ }
+}
+</programlisting>
+\endxmlonly
+*/
+ +namespace boost { namespace process { namespace detail {
+ + +struct cmd_
+{
+ constexpr cmd_() {}
+ + template<typename Char>
+ inline api::cmd_setter_<Char> operator()(const Char *s) const
+ {
+ return api::cmd_setter_<Char>(s);
+ }
+ template<typename Char>
+ inline api::cmd_setter_<Char> operator= (const Char *s) const
+ {
+ return api::cmd_setter_<Char>(s);
+ }
+ + template<typename Char>
+ inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
+ {
+ return api::cmd_setter_<Char>(s);
+ }
+ template<typename Char>
+ inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
+ {
+ return api::cmd_setter_<Char>(s);
+ }
+};
+ +template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
+ + + +template<>
+struct char_converter<char, api::cmd_setter_<wchar_t>>
+{
+ static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
+ {
+ return { ::boost::process::detail::convert(in.str()) };
+ }
+};
+ +template<>
+struct char_converter<wchar_t, api::cmd_setter_<char>>
+{
+ static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
+ {
+ return { ::boost::process::detail::convert(in.str()) };
+ }
+};
+ + + + + + +}
+ + +/** The cmd property allows to explicitly set commands for the execution.
+ +The overload form applies when only one string is passed to a launching function.
+The string will be internally parsed and split at spaces.
+ +The following expressions are valid, with `value` being either a C-String or
+a `std::basic_string` with `char` or `wchar_t`.
+ +\code{.cpp}
+cmd="value";
+cmd(value);
+\endcode
+ +The property can only be used for assignments.
+ + + */
+constexpr static ::boost::process::detail::cmd_ cmd;
+ +}}
+ +#endif
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_ */ diff --git a/boost/process/env.hpp b/boost/process/env.hpp new file mode 100644 index 0000000000..4362b0fe86 --- /dev/null +++ b/boost/process/env.hpp @@ -0,0 +1,502 @@ +// Copyright (c) 2016 Klemens D. Morgenstern
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ +#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
+#define BOOST_PROCESS_DETAIL_ENV_HPP_
+ +#include <boost/process/environment.hpp>
+#include <boost/none.hpp>
+ +#if defined(BOOST_POSIX_API)
+#include <boost/process/detail/posix/env_init.hpp>
+#elif defined(BOOST_WINDOWS_API)
+#include <boost/process/detail/windows/env_init.hpp>
+#endif
+ +/** \file boost/process/env.hpp
+ *
+ * This header which provides the `env` property. It allows the modification of the
+ * environment the child process will run in, in a functional style.
+ *
+ * \xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
+ }
+}
+</programlisting>
+ * \endxmlonly
+ *
+ * For additional information see the platform documentations:
+ *
+ * - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
+ * - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
+ *
+ */
+ + +namespace boost {
+ +namespace process { namespace detail {
+ + +template<typename Char>
+std::size_t make_env_string_size(const std::basic_string<Char> & ch)
+{
+ return ch.size() + 1;
+}
+ +template<typename Char>
+std::size_t make_env_string_size(const Char * ch)
+{
+ std::size_t sz = 0;
+ while (ch[sz] != null_char<Char>())
+ sz++;
+ + sz++;
+ return sz;
+}
+ +template<typename Char, typename Container>
+inline std::basic_string<Char> make_env_string(const Container & value)
+{
+ std::size_t sz = 0;
+ for (auto & v : value)
+ sz += make_env_string_size(v);
+ + std::basic_string<Char> s;
+ s.reserve(sz); //+1 for ;, end doesn't have one.
+ + for (auto & val : value)
+ (s += val) += api::env_seperator<Char>();
+ + s.resize(s.size() -1); //remove last ';'
+ return s;
+}
+ + +template<typename Char>
+struct env_set
+{
+ using string_type = std::basic_string<Char>;
+ string_type key;
+ string_type value;
+};
+ +template<typename Char>
+struct env_append
+{
+ using string_type = std::basic_string<Char>;
+ string_type key;
+ string_type value;
+};
+ + + +template<typename Char>
+struct env_reset
+{
+ using string_type = std::basic_string<Char>;
+ string_type key;
+};
+ + +template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
+template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
+template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
+template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
+ + +template<>
+struct char_converter<char, env_set<wchar_t>>
+{
+ static env_set<char> conv(const env_set<wchar_t> & in)
+ {
+ return {::boost::process::detail::convert(in.key),
+ ::boost::process::detail::convert(in.value)};
+ }
+};
+ +template<>
+struct char_converter<wchar_t, env_set<char>>
+{
+ static env_set<wchar_t> conv(const env_set<char> & in)
+ {
+ return {::boost::process::detail::convert(in.key),
+ ::boost::process::detail::convert(in.value)};
+ }
+};
+ +template<>
+struct char_converter<char, env_append<wchar_t>>
+{
+ static env_append<char> conv(const env_append<wchar_t> & in)
+ {
+ return {::boost::process::detail::convert(in.key),
+ ::boost::process::detail::convert(in.value)};
+ }
+};
+ +template<>
+struct char_converter<wchar_t, env_append<char>>
+{
+ static env_append<wchar_t> conv(const env_append<char> & in)
+ {
+ return {::boost::process::detail::convert(in.key),
+ ::boost::process::detail::convert(in.value)};
+ }
+};
+ +template<>
+struct char_converter<char, env_reset<wchar_t>>
+{
+ static env_reset<char> conv(const env_reset<wchar_t> & in)
+ {
+ return {::boost::process::detail::convert(in.key)};
+ }
+};
+ +template<>
+struct char_converter<wchar_t, env_reset<char>>
+{
+ static env_reset<wchar_t> conv(const env_reset<char> & in)
+ {
+ return {::boost::process::detail::convert(in.key)};
+ }
+};
+ + +template<typename Char>
+struct env_init
+{
+ basic_environment<Char> env;
+};
+ +template<>
+struct char_converter<char, env_init<wchar_t>>
+{
+ static env_init<char> conv(const env_init<wchar_t> & in)
+ {
+ return {basic_environment<char>(in.env)};
+ }
+};
+ +template<>
+struct char_converter<wchar_t, env_init<char>>
+{
+ static env_init<wchar_t> conv(const env_init<char> & in)
+ {
+ return {basic_environment<wchar_t>(in.env)};
+ }
+};
+ +template<>
+struct char_converter<char, basic_environment<wchar_t>>
+{
+ static basic_environment<char> conv(const basic_environment<wchar_t> & in)
+ {
+ return { basic_environment<char>(in) };
+ }
+};
+ +template<>
+struct char_converter<wchar_t, basic_environment<char>>
+{
+ static basic_environment<wchar_t> conv(const basic_environment<char> & in)
+ {
+ return { basic_environment<wchar_t>(in) };
+ }
+};
+ +template<typename Char>
+struct env_proxy
+{
+ using string_type = std::basic_string<Char>;
+ string_type key;
+ + + env_set<Char> operator=(const string_type & value)
+ {
+ return {std::move(key), value};
+ }
+ env_set<Char> operator=(const std::vector<string_type> & value)
+ {
+ return {std::move(key), make_env_string<Char>(value)};
+ }
+ env_set<Char> operator=(const std::initializer_list<const Char*> & value)
+ {
+ return {std::move(key), make_env_string<Char>(value)};
+ }
+ + env_append<Char> operator+=(const string_type & value)
+ {
+ return {std::move(key), value};
+ }
+ env_append<Char> operator+=(const std::vector<string_type> & value)
+ {
+ return {std::move(key), make_env_string<Char>(value)};
+ }
+ env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
+ {
+ return {std::move(key), make_env_string<Char>(value)};
+ }
+ env_reset<Char> operator=(boost::none_t)
+ {
+ return {std::move(key)};
+ }
+};
+ +struct env_
+{
+ constexpr env_() {};
+ + template<typename Char>
+ env_set<Char> operator()(const std::basic_string<Char> & key,
+ const std::basic_string<Char> & value) const
+ {
+ return {key, value};
+ }
+ template<typename Char>
+ env_set<Char> operator()(const std::basic_string<Char> & key,
+ const std::vector<std::basic_string<Char>> & value) const
+ {
+ return {key, make_env_string<Char>(value)};
+ }
+ template<typename Char>
+ env_set<Char> operator()(const std::basic_string<Char> & key,
+ const std::initializer_list<Char*> & value) const
+ {
+ return {key, make_env_string<Char>(value)};
+ }
+ template<typename Char>
+ env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
+ {
+ return {key};
+ }
+ template<typename Char>
+ env_proxy<Char> operator[](const std::basic_string<Char> & key) const
+ {
+ return {key};
+ }
+ template<typename Char>
+ env_proxy<Char> operator[](const Char* key) const
+ {
+ return {key};
+ }
+ template<typename Char>
+ env_init<Char> operator()(const basic_environment<Char> & env) const
+ {
+ return {env};
+ }
+ template<typename Char>
+ env_init<Char> operator= (const basic_environment<Char> & env) const
+ {
+ return {env};
+ }
+};
+ +template<typename Char>
+struct env_builder
+{
+ basic_environment<Char> env;
+ env_builder() : env{basic_native_environment<Char>()} {}
+
+ void operator()(const basic_environment<Char> & e)
+ {
+ env = e;
+ }
+ + void operator()(env_init<Char> & ei)
+ {
+ env = std::move(ei.env);
+ }
+ void operator()(env_set<Char> & es)
+ {
+ env[es.key] = es.value;
+ }
+ void operator()(env_reset<Char> & es)
+ {
+ env.erase(es.key);
+ }
+ template<typename T>
+ void operator()(env_append<T> & es)
+ {
+ env[es.key] += es.value;
+ }
+ + typedef api::env_init<Char> result_type;
+ api::env_init<Char> get_initializer()
+ {
+ return api::env_init<Char>(std::move(env));
+ }
+};
+ +template<>
+struct initializer_builder<env_tag<char>>
+{
+ typedef env_builder<char> type;
+};
+ +template<>
+struct initializer_builder<env_tag<wchar_t>>
+{
+ typedef env_builder<wchar_t> type;
+};
+ +}
+ +/**
+ +The `env` property provides a functional way to modify the environment used by
+the child process. If none is passed the environment is inherited from the father
+process. Appending means that the environment will be interpreted as a ';' or ':'
+seperated list as used in `PATH`.
+ +On both `posix` and `windows` the environment variables can be lists of strings,
+seperated by ';'. This is typically used for the `PATH` variable.
+ +By default the environment will be inherited from the launching process,
+which is also true if environment are modified with this initializer.
+ +\section env_details Details
+ +\subsection env_operations Operations
+ +\subsubsection env_set_var Setting variables
+ +To set a variable `id` the value `value` the following syntax can be used.
+ +\code{.cpp}
+env[id] = value;
+env(id, value);
+\endcode
+ +`std::initializer_list` is among the allowed types, so the following syntax is also possible.
+ +\code{.cpp}
+env[id] = {value1, value2};
+env(id, {value1, value2});
+\endcode
+ +\note Creates the variable if it does not exist.
+ +The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
+for both `id` and `value`.
+ +\paragraph id id
+ + - `std::basic_string<char_type>`
+ - `const char_type *`
+ +\paragraph env_set_var_value value
+ + - `std::basic_string<char_type>`
+ - `const char_type * `
+ - `std::initializer_list<const char_type *>`
+ - `std::vector<std::basic_string<char_type>>`
+ + +\note Using `std::vector` or `std::initializer_list`
+ +\subsubsection env_append_var Append variables
+ +Appending means, that a variable will be interpreted as a
+To append a variable `id` the value `value` the following syntax can be used:
+ +\code{.cpp}
+env[id] += value;
+\endcode
+ +`std::initializer_list` is among the allowed types, so the following syntax is also possible.
+ +\code{.cpp}
+env[id] += {value1, value2};
+\endcode
+ +\note Creates the variable if it does not exist.
+ +The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
+for both `id` and `value`.
+ +\paragraph env_append_var_id id
+ + - `std::basic_string<char_type>`
+ - `const char_type *`
+ +\paragraph env_append_var_value value
+ + - `std::basic_string<char_type>`
+ - `const char_type *`
+ - `std::initializer_list<const char_type *>`
+ - `std::vector<std::basic_string<char_type>>`
+ + +\subsubsection env_reset Reset variables
+ +Reseting signle variables can be done in the following way:
+ +\code{.cpp}
+env[id] = boost::none;
+env(id, boost::none);
+\endcode
+ +\note This does not set the value empty, but removes it from the list.
+ +The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
+ +\paragraph env_reset_var_id id
+ + - `std::basic_string<char_type>`
+ - `const char_type *`
+ +\subsubsection env_init Initialize the environment
+ +The whole environment can be initialized from an object of type
+\xmlonly <classname>boost::process::environment</classname> \endxmlonly
+ +\code{.cpp}
+env=env;
+env(env);
+\endcode
+ +\note The passed `environment` can also be default-constructed to get an empty environment.
+ +\paragraph env_init_var_id id
+ + - `std::basic_string<char_type>`
+ - `const char_type *`
+ +\paragraph env_init_var_value value
+ + - `boost::process::basic_environment<char_type>`
+ +\subsection env_example Example
+ +\code{.cpp}
+spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
+\endcode
+ +If the overload style should be done by passing an instance of
+\xmlonly <classname>boost::process::environment</classname> \endxmlonly
+the above example would look like this.
+ +\code{.cpp}
+environment e = this_process::environment();
+e["PATH"] += "F:/boost";
+e.erase("SOME_VAR");
+e["NEW_VAR"] = "VALUE";
+spawn("b2", e);
+\endcode
+ +\warning Passing an empty environment will cause undefined behaviour.
+ + */
+constexpr boost::process::detail::env_ env{};
+ + +}}
+ +#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
diff --git a/boost/process/environment.hpp b/boost/process/environment.hpp new file mode 100644 index 0000000000..1684798b87 --- /dev/null +++ b/boost/process/environment.hpp @@ -0,0 +1,698 @@ +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_PROCESS_ENVIRONMENT_HPP_ +#define BOOST_PROCESS_ENVIRONMENT_HPP_ + +#include <boost/process/detail/config.hpp> +#include <boost/algorithm/string/split.hpp> +#include <boost/algorithm/string/case_conv.hpp> +#include <boost/iterator/transform_iterator.hpp> +#include <boost/filesystem/path.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/environment.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/environment.hpp> +#endif + +namespace boost { namespace process { + +namespace detail { + +template<typename Char, typename Environment> +struct const_entry +{ + using value_type = Char ; + using pointer = const value_type * ; + using string_type = std::basic_string<value_type> ; + using range = boost::iterator_range<pointer> ; + using environment_t = Environment ; + + std::vector<string_type> to_vector() const + { + if (_data == nullptr) + return std::vector<string_type>(); + std::vector<string_type> data; + auto str = string_type(_data); + struct splitter + { + bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();} + bool operator()(char c) const {return c == api::env_seperator<char> ();} + } s; + boost::split(data, _data, s); + return std::move(data); + } + string_type to_string() const + { + if (_data != nullptr) + return string_type(_data); + else + return string_type(); + } + string_type get_name() const {return string_type(_name.begin(), _name.end());} + explicit const_entry(string_type&& name, pointer data, environment_t & env_) : + _name(std::move(name)), _data(data), _env(&env_) {} + + explicit const_entry(string_type &&name, environment_t & env) : + _name(std::move(name)), _data(nullptr), _env(&env) {} + const_entry(const const_entry&) = default; + const_entry& operator=(const const_entry&) = default; + + void reload() + { + auto p = _env->find(_name); + if (p == _env->end()) + _data = nullptr; + else + _data = p->_data; + this->_env->reload(); + + } + bool empty() const + { + return _data == nullptr; + } +protected: + string_type _name; + pointer _data; + environment_t * _env; +}; + +template<typename Char, typename Environment> +struct entry : const_entry<Char, Environment> +{ + using father = const_entry<Char, Environment>; + using value_type = typename father::value_type; + using string_type = typename father::string_type; + using pointer = typename father::pointer; + using environment_t = typename father::environment_t; + + explicit entry(string_type&& name, pointer data, environment_t & env) : + father(std::move(name), data, env) {} + + explicit entry(string_type &&name, environment_t & env) : + father(std::move(name), env) {} + + entry(const entry&) = default; + entry& operator=(const entry&) = default; + + void assign(const string_type &value) + { + this->_env->set(this->_name, value); + this->reload(); + } + void assign(const std::vector<string_type> &value) + { + string_type data; + for (auto &v : value) + { + if (&v != &value.front()) + data += api::env_seperator<value_type>(); + data += v; + } + this->_env->set(this->_name, data); + this->reload(); + + } + void assign(const std::initializer_list<string_type> &value) + { + string_type data; + for (auto &v : value) + { + if (&v != &*value.begin()) + data += api::env_seperator<value_type>(); + data += v; + } + this->_env->set(this->_name, data); + this->reload(); + + } + void append(const string_type &value) + { + if (this->_data == nullptr) + this->_env->set(this->_name, value); + else + { + string_type st = this->_data; + this->_env->set(this->_name, st + api::env_seperator<value_type>() + value); + } + + + this->reload(); + + } + void clear() + { + this->_env->reset(this->_name); + this->_env->reload(); + this->_data = nullptr; + } + entry &operator=(const string_type & value) + { + assign(value); + return *this; + } + entry &operator=(const std::vector<string_type> & value) + { + assign(value); + return *this; + } + entry &operator=(const std::initializer_list<string_type> & value) + { + assign(value); + return *this; + } + entry &operator+=(const string_type & value) + { + append(value); + return *this; + } + +}; + + + +template<typename Char, typename Environment> +struct make_entry +{ + + make_entry(const make_entry&) = default; + make_entry& operator=(const make_entry&) = default; + + Environment *env; + make_entry(Environment & env) : env(&env) {}; + entry<Char, Environment> operator()(const Char* data) const + { + auto p = data; + while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) + p++; + auto name = std::basic_string<Char>(data, p); + p++; //go behind equal sign + + return entry<Char, Environment>(std::move(name), p, *env); + } +}; + +template<typename Char, typename Environment> +struct make_const_entry +{ + + make_const_entry(const make_const_entry&) = default; + make_const_entry& operator=(const make_const_entry&) = default; + + Environment *env; + make_const_entry(Environment & env) : env(&env) {}; + const_entry<Char, Environment> operator()(const Char* data) const + { + auto p = data; + while ((*p != equal_sign<Char>()) && (*p != null_char<Char>())) + p++; + auto name = std::basic_string<Char>(data, p); + p++; //go behind equal sign + + return const_entry<Char, Environment>(std::move(name), p, *env); + } +}; + +} + +#if !defined (BOOST_PROCESS_DOXYGEN) + +template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl> +class basic_environment_impl : public Implementation<Char> +{ + Char** _get_end() const + { + auto p = this->_env_impl; + while (*p != nullptr) + p++; + + return p; + } +public: + using string_type = std::basic_string<Char>; + using implementation_type = Implementation<Char>; + using base_type = basic_environment_impl<Char, Implementation>; + using entry_maker = detail::make_entry<Char, base_type>; + using entry_type = detail::entry <Char, base_type>; + using const_entry_type = detail::const_entry <Char, const base_type>; + using const_entry_maker = detail::make_const_entry<Char, const base_type>; + + friend entry_type; + friend const_entry_type; + + using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>; + using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>; + using size_type = std::size_t; + + iterator begin() {return iterator(this->_env_impl, entry_maker(*this));} + const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} + const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));} + + iterator end() {return iterator(_get_end(), entry_maker(*this));} + const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));} + const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));} + + iterator find( const string_type& key ) + { + auto p = this->_env_impl; + auto st1 = key + ::boost::process::detail::equal_sign<Char>(); + while (*p != nullptr) + { + if (std::equal(st1.begin(), st1.end(), *p)) + break; + p++; + } + return iterator(p, entry_maker(*this)); + } + const_iterator find( const string_type& key ) const + { + auto p = this->_env_impl; + auto st1 = key + ::boost::process::detail::equal_sign<Char>(); + while (*p != nullptr) + { + if (std::equal(st1.begin(), st1.end(), *p)) + break; + p++; + } + return const_iterator(p, const_entry_maker(*this)); + } + + std::size_t count(const string_type & st) const + { + auto p = this->_env_impl; + auto st1 = st + ::boost::process::detail::equal_sign<Char>(); + while (*p != nullptr) + { + if (std::equal(st1.begin(), st1.end(), *p)) + return 1u; + p++; + } + return 0u; + } + void erase(const string_type & id) + { + implementation_type::reset(id); + this->reload(); + } + std::pair<iterator,bool> emplace(const string_type & id, const string_type & value) + { + auto f = find(id); + if (f == end()) + { + implementation_type::set(id, value); + this->reload(); + return std::pair<iterator, bool>(find(id), true); + } + else + return std::pair<iterator, bool>(f, false); + } + using implementation_type::implementation_type; + using implementation_type::operator=; + using native_handle_type = typename implementation_type::native_handle_type; + using implementation_type::native_handle; + //copy ctor if impl is copy-constructible + bool empty() + { + return *this->_env_impl == nullptr; + } + std::size_t size() const + { + return (_get_end() - this->_env_impl); + } + void clear() + { + std::vector<string_type> names; + names.resize(size()); + std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();}); + + for (auto & nm : names) + implementation_type::reset(nm); + + this->reload(); + } + + entry_type at( const string_type& key ) + { + auto f = find(key); + if (f== end()) + throw std::out_of_range(key + " not found"); + return *f; + } + const_entry_type at( const string_type& key ) const + { + auto f = find(key); + if (f== end()) + throw std::out_of_range(key + " not found"); + return *f; + } + entry_type operator[](const string_type & key) + { + auto p = find(key); + if (p != end()) + return *p; + + return entry_type(string_type(key), *this); + } +}; +#endif + +#if defined(BOOST_PROCESS_DOXYGEN) +/**Template representation of environments. It takes a character type (`char` or `wchar_t`) + * as template parameter to implement the environment + */ +template<typename Char> +class basic_environment +{ + +public: + typedef std::basic_string<Char> string_type; + typedef boost::transform_iterator< entry_maker, Char**> iterator ; + typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; + typedef std::size_t size_type ; + + iterator begin() ; ///<Returns an iterator to the beginning + const_iterator begin() const ; ///<Returns an iterator to the beginning + const_iterator cbegin() const ; ///<Returns an iterator to the beginning + + iterator end() ; ///<Returns an iterator to the end + const_iterator end() const; ///<Returns an iterator to the end + const_iterator cend() const; ///<Returns an iterator to the end + + iterator find( const string_type& key ); ///<Find a variable by its name + const_iterator find( const string_type& key ) const; ///<Find a variable by its name + + std::size_t count(const string_type & st) const; ///<Number of variables + void erase(const string_type & id); ///<Erase variable by id. + ///Emplace an environment variable. + std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); + + ///Default constructor + basic_environment(); + ///Copy constructor. + basic_environment(const basic_environment & ); + ///Move constructor. + basic_environment(basic_environment && ); + + ///Copy assignment. + basic_environment& operator=(const basic_environment & ); + ///Move assignment. + basic_environment& operator=(basic_environment && ); + + typedef typename detail::implementation_type::native_handle_type native_handle; + + ///Check if environment has entries. + bool empty(); + ///Get the number of variables. + std::size_t size() const; + ///Clear the environment. @attention Use with care, passed environment cannot be empty. + void clear(); + ///Get the entry with the key. Throws if it does not exist. + entry_type at( const string_type& key ); + ///Get the entry with the key. Throws if it does not exist. + const_entry_type at( const string_type& key ) const; + ///Get the entry with the given key. It creates the entry if it doesn't exist. + entry_type operator[](const string_type & key); + + /**Proxy class used for read access to members by [] or .at() + * @attention Holds a reference to the environment it was created from. + */ + template<typename Char, typename Environment> + struct const_entry_type + { + typedef Char value_type; + typedef const value_type * pointer; + typedef std::basic_string<value_type> string_type; + typedef boost::iterator_range<pointer> range; + typedef Environment environment_t; + + ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. + std::vector<string_type> to_vector() const + ///Get the value as string. + string_type to_string() const + ///Get the name of this entry. + string_type get_name() const {return string_type(_name.begin(), _name.end());} + ///Copy Constructor + const_entry(const const_entry&) = default; + ///Move Constructor + const_entry& operator=(const const_entry&) = default; + ///Check if the entry is empty. + bool empty() const; + }; + + /**Proxy class used for read and write access to members by [] or .at() + * @attention Holds a reference to the environment it was created from. + */ + template<typename Char, typename Environment> + struct entry_type + { + + typedef Char value_type; + typedef const value_type * pointer; + typedef std::basic_string<value_type> string_type; + typedef boost::iterator_range<pointer> range; + typedef Environment environment_t; + + ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. + std::vector<string_type> to_vector() const + ///Get the value as string. + string_type to_string() const + ///Get the name of this entry. + string_type get_name() const {return string_type(_name.begin(), _name.end());} + ///Copy Constructor + entry(const entry&) = default; + ///Move Constructor + entry& operator=(const entry&) = default; + ///Check if the entry is empty. + bool empty() const; + + ///Assign a string to the value + void assign(const string_type &value); + ///Assign a set of strings to the entry; they will be seperated by ';' or ':'. + void assign(const std::vector<string_type> &value); + ///Append a string to the end of the entry, it will seperated by ';' or ':'. + void append(const string_type &value); + ///Reset the value + void clear(); + ///Assign a string to the entry. + entry &operator=(const string_type & value); + ///Assign a set of strings to the entry; they will be seperated by ';' or ':'. + entry &operator=(const std::vector<string_type> & value); + ///Append a string to the end of the entry, it will seperated by ';' or ':'. + entry &operator+=(const string_type & value); + }; + +}; + +/**Template representation of the environment of this process. It takes a template + * as template parameter to implement the environment. All instances of this class + * refer to the same environment, but might not get updated if another one makes changes. + */ +template<typename Char> +class basic_native_environment +{ + +public: + typedef std::basic_string<Char> string_type; + typedef boost::transform_iterator< entry_maker, Char**> iterator ; + typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ; + typedef std::size_t size_type ; + + iterator begin() ; ///<Returns an iterator to the beginning + const_iterator begin() const ; ///<Returns an iterator to the beginning + const_iterator cbegin() const ; ///<Returns an iterator to the beginning + + iterator end() ; ///<Returns an iterator to the end + const_iterator end() const; ///<Returns an iterator to the end + const_iterator cend() const; ///<Returns an iterator to the end + + iterator find( const string_type& key ); ///<Find a variable by its name + const_iterator find( const string_type& key ) const; ///<Find a variable by its name + + std::size_t count(const string_type & st) const; ///<Number of variables + void erase(const string_type & id); ///<Erase variable by id. + ///Emplace an environment variable. + std::pair<iterator,bool> emplace(const string_type & id, const string_type & value); + + ///Default constructor + basic_native_environment(); + ///Move constructor. + basic_native_environment(basic_native_environment && ); + ///Move assignment. + basic_native_environment& operator=(basic_native_environment && ); + + typedef typename detail::implementation_type::native_handle_type native_handle; + + ///Check if environment has entries. + bool empty(); + ///Get the number of variables. + std::size_t size() const; + ///Get the entry with the key. Throws if it does not exist. + entry_type at( const string_type& key ); + ///Get the entry with the key. Throws if it does not exist. + const_entry_type at( const string_type& key ) const; + ///Get the entry with the given key. It creates the entry if it doesn't exist. + entry_type operator[](const string_type & key); + + /**Proxy class used for read access to members by [] or .at() + * @attention Holds a reference to the environment it was created from. + */ + template<typename Char, typename Environment> + struct const_entry_type + { + typedef Char value_type; + typedef const value_type * pointer; + typedef std::basic_string<value_type> string_type; + typedef boost::iterator_range<pointer> range; + typedef Environment environment_t; + + ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. + std::vector<string_type> to_vector() const + ///Get the value as string. + string_type to_string() const + ///Get the name of this entry. + string_type get_name() const {return string_type(_name.begin(), _name.end());} + ///Copy Constructor + const_entry(const const_entry&) = default; + ///Move Constructor + const_entry& operator=(const const_entry&) = default; + ///Check if the entry is empty. + bool empty() const; + }; + + /**Proxy class used for read and write access to members by [] or .at() + * @attention Holds a reference to the environment it was created from. + */ + template<typename Char, typename Environment> + struct entry_type + { + + typedef Char value_type; + typedef const value_type * pointer; + typedef std::basic_string<value_type> string_type; + typedef boost::iterator_range<pointer> range; + typedef Environment environment_t; + + ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. + std::vector<string_type> to_vector() const + ///Get the value as string. + string_type to_string() const + ///Get the name of this entry. + string_type get_name() const {return string_type(_name.begin(), _name.end());} + ///Copy Constructor + entry(const entry&) = default; + ///Move Constructor + entry& operator=(const entry&) = default; + ///Check if the entry is empty. + bool empty() const; + + ///Assign a string to the value + void assign(const string_type &value); + ///Assign a set of strings to the entry; they will be seperated by ';' or ':'. + void assign(const std::vector<string_type> &value); + ///Append a string to the end of the entry, it will seperated by ';' or ':'. + void append(const string_type &value); + ///Reset the value + void clear(); + ///Assign a string to the entry. + entry &operator=(const string_type & value); + ///Assign a set of strings to the entry; they will be seperated by ';' or ':'. + entry &operator=(const std::vector<string_type> & value); + ///Append a string to the end of the entry, it will seperated by ';' or ':'. + entry &operator+=(const string_type & value); + }; + +}; + +#endif + +///Definition of the environment for the current process. +template<typename Char> +class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl> +{ +public: + using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>; + using base_type::base_type; + using base_type::operator=; +}; + +///Type definition to hold a seperate environment. +template<typename Char> +class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl> +{ +public: + using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>; + using base_type::base_type; + using base_type::operator=; +}; + + + +///Definition of the environment for the current process. +typedef basic_native_environment<char> native_environment; +///Definition of the environment for the current process. +typedef basic_native_environment<wchar_t> wnative_environment; + +///Type definition to hold a seperate environment. +typedef basic_environment<char> environment; +///Type definition to hold a seperate environment. +typedef basic_environment<wchar_t> wenvironment; + +} + +///Namespace containing information of the calling process. +namespace this_process +{ + +///Definition of the native handle type. +typedef ::boost::process::detail::api::native_handle_t native_handle_type; + +///Definition of the environment for this process. +using ::boost::process::native_environment; +///Definition of the environment for this process. +using ::boost::process::wnative_environment; + +///Get the process id of the current process. +inline int get_id() { return ::boost::process::detail::api::get_id();} +///Get the native handle of the current process. +inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();} +///Get the enviroment of the current process. +inline native_environment environment() { return ::boost::process:: native_environment(); } +///Get the enviroment of the current process. +inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); } +///Get the path environment variable of the current process runs. +inline std::vector<boost::filesystem::path> path() +{ +#if defined(BOOST_WINDOWS_API) + const ::boost::process::wnative_environment ne{}; + typedef typename ::boost::process::wnative_environment::const_entry_type value_type; + const auto id = L"PATH"; +#else + const ::boost::process::native_environment ne{}; + typedef typename ::boost::process::native_environment::const_entry_type value_type; + const auto id = "PATH"; +#endif + + auto itr = std::find_if(ne.cbegin(), ne.cend(), + [&](const value_type & e) + {return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());}); + + if (itr == ne.cend()) + return {}; + + auto vec = itr->to_vector(); + + std::vector<boost::filesystem::path> val; + val.resize(vec.size()); + + std::copy(vec.begin(), vec.end(), val.begin()); + + return val; +} +} +} +#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */ diff --git a/boost/process/error.hpp b/boost/process/error.hpp new file mode 100644 index 0000000000..f70cce6c83 --- /dev/null +++ b/boost/process/error.hpp @@ -0,0 +1,211 @@ +// 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_ERROR_HPP +#define BOOST_PROCESS_DETAIL_ERROR_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/traits.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 + +#include <system_error> + +#include <type_traits> +#include <boost/fusion/algorithm/query/find_if.hpp> +#include <boost/fusion/sequence/intrinsic/begin.hpp> +#include <boost/fusion/sequence/intrinsic/end.hpp> +#include <boost/fusion/container/vector/convert.hpp> +#include <boost/fusion/iterator/deref.hpp> +#include <boost/fusion/sequence/comparison/equal_to.hpp> +#include <boost/fusion/container/set/convert.hpp> +#include <boost/type_index.hpp> + +/** \file boost/process/error.hpp + * + * Header which provides the error properties. It allows to explicitly set the error handling, the properties are: + * +\xmlonly +<programlisting> +namespace boost { + namespace process { + <emphasis>unspecified</emphasis> <globalname alt="boost::process::ignore_error">ignore_error</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::throw_on_error">throw_on_error</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::error">error</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_ref">error_ref</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_code">error_code</globalname>; + } +} +</programlisting> +\endxmlonly + * For error there are two aliases: error_ref and error_code + */ + +namespace boost { namespace process { + +namespace detail { + +struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext +{ + constexpr throw_on_error_() {}; + + template <class Executor> + void on_error(Executor&, const std::error_code & ec) const + { + throw process_error(ec, "process creation failed"); + } + + const throw_on_error_ &operator()() const {return *this;} +}; + +struct ignore_error_ : ::boost::process::detail::api::handler_base_ext +{ + constexpr ignore_error_() {}; +}; + +struct set_on_error : ::boost::process::detail::api::handler_base_ext +{ + set_on_error(const set_on_error&) = default; + explicit set_on_error(std::error_code &ec) : ec_(ec) {} + + template <class Executor> + void on_error(Executor&, const std::error_code & ec) const + { + ec_ = ec; + } + +private: + std::error_code &ec_; +}; + +struct error_ +{ + constexpr error_() {} + set_on_error operator()(std::error_code &ec) const {return set_on_error(ec);} + set_on_error operator= (std::error_code &ec) const {return set_on_error(ec);} + +}; + + +template<typename T> +struct is_error_handler : std::false_type {}; + +template<> struct is_error_handler<set_on_error> : std::true_type {}; +template<> struct is_error_handler<throw_on_error_> : std::true_type {}; +template<> struct is_error_handler<ignore_error_> : std::true_type {}; + + + +template<typename Iterator, typename End> +struct has_error_handler_impl +{ + typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type; + typedef typename std::remove_reference<ref_type>::type res_type_; + typedef typename std::remove_cv<res_type_>::type res_type; + typedef typename is_error_handler<res_type>::type cond; + + typedef typename boost::fusion::result_of::next<Iterator>::type next_itr; + typedef typename has_error_handler_impl<next_itr, End>::type next; + + typedef typename boost::mpl::or_<cond, next>::type type; +}; + +template<typename Iterator> +struct has_error_handler_impl<Iterator, Iterator> +{ + typedef boost::mpl::false_ type; +}; + + +template<typename Sequence> +struct has_error_handler +{ + typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type; + + typedef typename has_error_handler_impl< + typename boost::fusion::result_of::begin<vector_type>::type, + typename boost::fusion::result_of::end< vector_type>::type + >::type type; +}; + +template<typename Sequence> +struct has_ignore_error +{ + typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type; + typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_>::type type1; + typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2; + typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3; + typedef typename boost::mpl::or_<type1,type2, type3>::type type; +}; + +struct error_builder +{ + std::error_code *err; + typedef set_on_error result_type; + set_on_error get_initializer() {return set_on_error(*err);}; + void operator()(std::error_code & ec) {err = &ec;}; +}; + +template<> +struct initializer_tag<std::error_code> +{ + typedef error_tag type; +}; + + +template<> +struct initializer_builder<error_tag> +{ + typedef error_builder type; +}; + +} +/**The ignore_error property will disable any error handling. This can be useful +on linux, where error handling will require a pipe.*/ +constexpr boost::process::detail::ignore_error_ ignore_error; +/**The throw_on_error property will enable the exception when launching a process. +It is unnecessary by default, but may be used, when an additional error_code is provided.*/ +constexpr boost::process::detail::throw_on_error_ throw_on_error; +/** +The error property will set the executor to handle any errors by setting an +[std::error_code](http://en.cppreference.com/w/cpp/error/error_code). + +\code{.cpp} +std::error_code ec; +system("gcc", error(ec)); +\endcode + +The following syntax is valid: + +\code{.cpp} +error(ec); +error=ec; +\endcode + +The overload version is achieved by just passing an object of + [std::error_code](http://en.cppreference.com/w/cpp/error/error_code) to the function. + + + */ +constexpr boost::process::detail::error_ error; +///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly . +constexpr boost::process::detail::error_ error_ref; +///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly . +constexpr boost::process::detail::error_ error_code; + + +}} + +#endif diff --git a/boost/process/exception.hpp b/boost/process/exception.hpp new file mode 100644 index 0000000000..1bb391117a --- /dev/null +++ b/boost/process/exception.hpp @@ -0,0 +1,30 @@ +// 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_EXCEPTION_HPP_ +#define BOOST_PROCESS_EXCEPTION_HPP_ + +#include <system_error> + +namespace boost +{ +namespace process +{ +///The exception usually thrown by boost.process. +/** It merely inherits [std::system_error](http://en.cppreference.com/w/cpp/error/system_error) + * but can then be distinguished in the catch-block from other system errors. + * + */ +struct process_error : std::system_error +{ + using std::system_error::system_error; +}; + +} +} + + + +#endif /* BOOST_PROCESS_EXCEPTION_HPP_ */ diff --git a/boost/process/exe.hpp b/boost/process/exe.hpp new file mode 100644 index 0000000000..04a63bc754 --- /dev/null +++ b/boost/process/exe.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_EXE_HPP
+#define BOOST_PROCESS_EXE_HPP
+ +#include <boost/process/detail/basic_cmd.hpp>
+ +/** \file boost/process/exe.hpp
+ *
+ * Header which provides the exe property.
+\xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::exe">exe</globalname>;
+ }
+}
+</programlisting>
+\endxmlonly
+ */
+namespace boost { namespace process { namespace detail {
+ +struct exe_
+{
+ template<typename Char>
+ inline exe_setter_<Char> operator()(const Char *s) const
+ {
+ return exe_setter_<Char>(s);
+ }
+ template<typename Char>
+ inline exe_setter_<Char> operator= (const Char *s) const
+ {
+ return exe_setter_<Char>(s);
+ }
+ + template<typename Char>
+ inline exe_setter_<Char> operator()(const std::basic_string<Char> &s) const
+ {
+ return exe_setter_<Char>(s);
+ }
+ template<typename Char>
+ inline exe_setter_<Char> operator= (const std::basic_string<Char> &s) const
+ {
+ return exe_setter_<Char>(s);
+ }
+};
+ +}
+ +/** The exe property allows to explicitly set the executable.
+ +The overload form applies when to the first, when several strings are passed to a launching
+function.
+ +The following expressions are valid, with `value` being either a C-String or
+a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
+ +\code{.cpp}
+exe="value";
+exe(value);
+\endcode
+ +The property can only be used for assignments.
+ + + */
+constexpr boost::process::detail::exe_ exe{};
+ +}}
+ +#endif
diff --git a/boost/process/extend.hpp b/boost/process/extend.hpp new file mode 100644 index 0000000000..7496f30f16 --- /dev/null +++ b/boost/process/extend.hpp @@ -0,0 +1,339 @@ +// 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_EXTENSIONS_HPP_ +#define BOOST_PROCESS_EXTENSIONS_HPP_ + +#include <boost/process/detail/handler.hpp> + +#if defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/executor.hpp> +#include <boost/process/detail/windows/async_handler.hpp> +#include <boost/process/detail/windows/asio_fwd.hpp> +#else +#include <boost/process/detail/posix/executor.hpp> +#include <boost/process/detail/posix/async_handler.hpp> +#include <boost/process/detail/posix/asio_fwd.hpp> +#endif + + +/** \file boost/process/extend.hpp + * + * This header which provides the types and functions provided for custom extensions. + * + * \xmlonly + Please refer to the <link linkend="boost_process.extend">tutorial</link> for more details. + \endxmlonly + */ + + +namespace boost { +namespace process { +namespace detail { +template<typename Tuple> +inline asio::io_service& get_io_service(const Tuple & tup); +} + + +///Namespace for extensions \attention This is experimental. +namespace extend { + +#if defined(BOOST_WINDOWS_API) + +template<typename Char, typename Sequence> +using windows_executor = ::boost::process::detail::windows::executor<Char, Sequence>; +template<typename Sequence> +struct posix_executor; + +#elif defined(BOOST_POSIX_API) + +template<typename Sequence> +using posix_executor = ::boost::process::detail::posix::executor<Sequence>; +template<typename Char, typename Sequence> +struct windows_executor; + +#endif + +using ::boost::process::detail::handler; +using ::boost::process::detail::api::require_io_service; +using ::boost::process::detail::api::async_handler; +using ::boost::process::detail::get_io_service; +using ::boost::process::detail::get_last_error; +using ::boost::process::detail::throw_last_error; + +///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter. +constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup; +///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter. +constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error; +///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. +constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success; + +#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN) +///This handler is invoked if the fork failed. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix. +constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_fork_error_ > on_fork_error; +///This handler is invoked if the fork succeeded. The required signature is `void(Exec &)`, where `Exec` is a template parameter. \note Only available on posix. +constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_setup_ > on_exec_setup; +///This handler is invoked if the exec call errored. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix. +constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_error_ > on_exec_error; +#endif + +#if defined(BOOST_PROCESS_DOXYGEN) +///Helper function to get the last error code system-independent +inline std::error_code get_last_error(); + +///Helper function to get and throw the last system error. +/// \throws boost::process::process_error +/// \param msg A message to add to the error code. +inline void throw_last_error(const std::string & msg); +///\overload void throw_last_error(const std::string & msg) +inline void throw_last_error(); + + +/** This function gets the io_service from the initializer sequence. + * + * \attention Yields a compile-time error if no `io_service` is provided. + * \param seq The Sequence of the initializer. + */ +template<typename Sequence> +inline asio::io_service& get_io_service(const Sequence & seq); + +/** This class is the base for every initializer, to be used for extensions. + * + * The usage is done through compile-time polymorphism, so that the required + * functions can be overloaded. + * + * \note None of the function need to be `const`. + * + */ +struct handler +{ + ///This function is invoked before the process launch. \note It is not required to be const. + template <class Executor> + void on_setup(Executor&) const {} + + /** This function is invoked if an error occured while trying to launch the process. + * \note It is not required to be const. + */ + template <class Executor> + void on_error(Executor&, const std::error_code &) const {} + + /** This function is invoked if the process was successfully launched. + * \note It is not required to be const. + */ + template <class Executor> + void on_success(Executor&) const {} + + /**This function is invoked if an error occured during the call of `fork`. + * \note This function will only be called on posix. + */ + template<typename Executor> + void on_fork_error (Executor &, const std::error_code&) const {} + + /**This function is invoked if the call of `fork` was successful, before + * calling `execve`. + * \note This function will only be called on posix. + * \attention It will be invoked from the new process. + */ + template<typename Executor> + void on_exec_setup (Executor &) const {} + + /**This function is invoked if the call of `execve` failed. + * \note This function will only be called on posix. + * \attention It will be invoked from the new process. + */ + template<typename Executor> + void on_exec_error (Executor &, const std::error_code&) const {} + +}; + + +/** Inheriting the class will tell the launching process that an `io_service` is + * needed. This should always be used when \ref get_io_service is used. + * + */ +struct require_io_service {}; +/** Inheriting this class will tell the launching function, that an event handler + * shall be invoked when the process exits. This automatically does also inherit + * \ref require_io_service. + * + * You must add the following function to your implementation: + * + \code{.cpp} +template<typename Executor> +std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec) +{ + auto handler = this->handler; + return [handler](int exit_code, const std::error_code & ec) + { + handler(static_cast<int>(exit_code), ec); + }; + +} + \endcode + + The callback will be obtained by calling this function on setup and it will be + invoked when the process exits. + + * + * \warning Cannot be used with \ref boost::process::spawn + */ +struct async_handler : handler, require_io_service +{ + +}; + +///The posix executor type. +/** This type represents the posix executor and can be used for overloading in a custom handler. + * \note It is an alias for the implementation on posix, and a forward-declaration on windows. + * + * \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept. + + +\xmlonly +As information for extension development, here is the structure of the process launching (in pseudo-code and uml) +<xi:include href="posix_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> + +<mediaobject> +<caption> +<para>The sequence if when no error occurs.</para> +</caption> +<imageobject> +<imagedata fileref="boost_process/posix_success.svg"/> +</imageobject> +</mediaobject> + +<mediaobject> +<caption> +<para>The sequence if the execution fails.</para> +</caption> +<imageobject> +<imagedata fileref="boost_process/posix_exec_err.svg"/> +</imageobject> +</mediaobject> + +<mediaobject> +<caption> +<para>The sequence if the fork fails.</para> +</caption> +<imageobject> +<imagedata fileref="boost_process/posix_fork_err.svg"/> +</imageobject> +</mediaobject> + +\endxmlonly + + +\note Error handling if execve fails is done through a pipe, unless \ref ignore_error is used. + + */ +template<typename Sequence> +struct posix_executor +{ + ///A reference to the actual initializer-sequence + Sequence & seq; + ///A pointer to the name of the executable. + const char * exe = nullptr; + ///A pointer to the argument-vector. + char *const* cmd_line = nullptr; + ///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html) + char **env = ::environ; + ///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */ + pid_t pid = -1; + ///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_service` and \ref child. + std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); + + ///This function returns a const reference to the error state of the executor. + const std::error_code & error() const; + + ///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it + /// might throw an exception. \note This is the required way to handle errors in initializers. + void set_error(const std::error_code &ec, const std::string &msg); + ///\overload void set_error(const std::error_code &ec, const std::string &msg); + void set_error(const std::error_code &ec, const char* msg); +}; + +///The windows executor type. +/** This type represents the posix executor and can be used for overloading in a custom handler. + * + * \note It is an alias for the implementation on posix, and a forward-declaration on windows. + * \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept. + * \tparam Char The used char-type, either `char` or `wchar_t`. + * + +\xmlonly +As information for extension development, here is the structure of the process launching (in pseudo-code and uml)<xi:include href="windows_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> +<mediaobject> +<caption> +<para>The sequence for windows process creation.</para> +</caption> +<imageobject> +<imagedata fileref="boost_process/windows_exec.svg"/> +</imageobject> +</mediaobject> +\endxmlonly + + */ + +template<typename Char, typename Sequence> +struct windows_executor +{ + ///A reference to the actual initializer-sequence + Sequence & seq; + + ///A pointer to the name of the executable. It's null by default. + const Char * exe = nullptr; + ///A pointer to the argument-vector. Must be set by some initializer. + char Char* cmd_line = nullptr; + ///A pointer to the environment variables. It's null by default. + char Char* env = nullptr; + ///A pointer to the working directory. It's null by default. + const Char * work_dir = nullptr; + + ///A pointer to the process-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It's null by default. + ::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr; + ///A pointer to the thread-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It' null by default. + ::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr; + ///A logical bool value setting whether handles shall be inherited or not. + ::boost::detail::winapi::BOOL_ inherit_handles = false; + + ///The element holding the process-information after process creation. The type is [PROCESS_INFORMATION](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873.aspx) + ::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0}; + + + ///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_service` and \ref child. + std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active); + + ///This function returns a const reference to the error state of the executor. + const std::error_code & error() const; + + ///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it + /// might throw an exception. \note This is the required way to handle errors in initializers. + void set_error(const std::error_code &ec, const std::string &msg); + ///\overload void set_error(const std::error_code &ec, const std::string &msg); + void set_error(const std::error_code &ec, const char* msg); + + ///The creation flags of the process + ::boost::detail::winapi::DWORD_ creation_flags; + ///The type of the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx), depending on the char-type. + typedef typename detail::startup_info<Char>::type startup_info_t; + ///The type of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx), depending the char-type; only defined with winapi-version equal or higher than 6. + typedef typename detail::startup_info_ex<Char>::type startup_info_ex_t; + ///This function switches the information, so that the extended structure is used. \note It's only defined with winapi-version equal or higher than 6. + void set_startup_info_ex(); + ///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process. + startup_info_t startup_info; + ///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6. + startup_info_ex_t startup_info_ex; +}; + + + +#endif + +} +} +} + +#endif diff --git a/boost/process/group.hpp b/boost/process/group.hpp new file mode 100644 index 0000000000..b46f064475 --- /dev/null +++ b/boost/process/group.hpp @@ -0,0 +1,228 @@ +// 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/group.hpp + * + * Defines a group process class. + * For additional information see the platform specific implementations: + * + * - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx) + * - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html) + * + */ + +#ifndef BOOST_PROCESS_GROUP_HPP +#define BOOST_PROCESS_GROUP_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/child.hpp> +#include <chrono> +#include <memory> + +#include <boost/none.hpp> +#include <atomic> + + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/group_handle.hpp> +#include <boost/process/detail/posix/group_ref.hpp> +#include <boost/process/detail/posix/wait_group.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/group_handle.hpp> +#include <boost/process/detail/windows/group_ref.hpp> +#include <boost/process/detail/windows/wait_group.hpp> +#endif + +namespace boost { + +namespace process { + +namespace detail { + struct group_builder; +} + +/** + * Represents a process group. + * + * Groups are movable but non-copyable. The destructor + * automatically closes handles to the group process. + * + * The group will have the same interface as std::thread. + * + * \note If the destructor is called without a previous detach or wait, the group will be terminated. + * + * \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined. + * + * \attention Waiting for groups is currently broken on windows and will most likely result in a dead-lock. + */ +class group +{ + ::boost::process::detail::api::group_handle _group_handle; + bool _attached = true; +public: + typedef ::boost::process::detail::api::group_handle group_handle; + ///Native representation of the handle. + typedef group_handle::handle_t native_handle_t; + explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {} + ///Construct the group from a native_handle + explicit group(native_handle_t & handle) : _group_handle(handle) {}; + group(const group&) = delete; + ///Move constructor + group(group && lhs) + : _group_handle(std::move(lhs._group_handle)), + _attached (lhs._attached) + { + lhs._attached = false; + } + ///Default constructor + group() = default; + group& operator=(const group&) = delete; + ///Move assign + group& operator=(group && lhs) + { + _group_handle= std::move(lhs._group_handle); + _attached = lhs._attached; + + return *this; + }; + + ///Detach the group + void detach() {_attached = false; } + + /** Join the child. This just calls wait, but that way the naming is similar to std::thread */ + void join() {wait();} + /** Check if the child is joinable. */ + bool joinable() {return _attached;} + + /** Destructor + * + * \note If the destructor is called without a previous detach or wait, the group will be terminated. + * + */ + ~group() + { + std::error_code ec; + if ( _attached && valid()) + terminate(ec); + } + + ///Obtain the native handle of the group. + native_handle_t native_handle() const { return _group_handle.handle(); } + + ///Wait for the process group to exit. + void wait() + { + boost::process::detail::api::wait(_group_handle); + } + ///\overload void wait() + void wait(std::error_code & ec) noexcept + { + boost::process::detail::api::wait(_group_handle, ec); + } + /** Wait for the process group to exit for period of time. + * \return True if all child processes exited while waiting.*/ + template< class Rep, class Period > + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time) + { + return boost::process::detail::api::wait_for(_group_handle, rel_time); + } + + /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */ + template< class Rep, class Period > + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept + { + return boost::process::detail::api::wait_for(_group_handle, rel_time, ec); + } + + /** Wait for the process group to exit until a point in time. + * \return True if all child processes exited while waiting.*/ + template< class Clock, class Duration > + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) + { + return boost::process::detail::api::wait_until(_group_handle, timeout_time); + } + /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */ + template< class Clock, class Duration > + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept + { + return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec); + } + + ///Check if the group has a valid handle. + bool valid() const + { + return _group_handle.valid(); + } + ///Convenience to call valid. + explicit operator bool() const {return valid();} + + ///Terminate the process group, i.e. all processes in the group + void terminate() + { + ::boost::process::detail::api::terminate(_group_handle); + } + ///\overload void terminate() + void terminate(std::error_code & ec) noexcept + { + ::boost::process::detail::api::terminate(_group_handle, ec); + } + + ///Assign a child process to the group + void add(const child &c) + { + _group_handle.add(c.native_handle()); + } + ///\overload void assign(const child & c) + void add(const child &c, std::error_code & ec) noexcept + { + _group_handle.add(c.native_handle(), ec); + } + + ///Check if the child process is in the group + bool has(const child &c) + { + return _group_handle.has(c.native_handle()); + } + ///\overload bool has(const child &) + bool has(const child &c, std::error_code & ec) noexcept + { + return _group_handle.has(c.native_handle(), ec); + + } + + friend struct detail::group_builder; +}; + +namespace detail +{ + +struct group_tag; +struct group_builder +{ + group * group_p; + + void operator()(group & grp) {this->group_p = &grp;}; + + typedef api::group_ref result_type; + api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);}; +}; + +template<> +struct initializer_tag<group> +{ + typedef group_tag type; +}; + +template<> +struct initializer_builder<group_tag> +{ + typedef group_builder type; +}; + +} +}} +#endif + diff --git a/boost/process/io.hpp b/boost/process/io.hpp new file mode 100644 index 0000000000..85a143ca31 --- /dev/null +++ b/boost/process/io.hpp @@ -0,0 +1,551 @@ +// 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_IO_HPP_
+#define BOOST_PROCESS_IO_HPP_
+ +#include <iosfwd>
+#include <cstdio>
+#include <functional>
+#include <utility>
+#include <boost/process/detail/config.hpp>
+#include <boost/process/pipe.hpp>
+ +#include <future>
+ +#if defined(BOOST_POSIX_API)
+#include <boost/process/detail/posix/asio_fwd.hpp>
+#include <boost/process/detail/posix/close_in.hpp>
+#include <boost/process/detail/posix/close_out.hpp>
+#include <boost/process/detail/posix/null_in.hpp>
+#include <boost/process/detail/posix/null_out.hpp>
+#include <boost/process/detail/posix/file_in.hpp>
+#include <boost/process/detail/posix/file_out.hpp>
+#include <boost/process/detail/posix/pipe_in.hpp>
+#include <boost/process/detail/posix/pipe_out.hpp>
+#elif defined(BOOST_WINDOWS_API)
+#include <boost/process/detail/windows/asio_fwd.hpp>
+#include <boost/process/detail/windows/close_in.hpp>
+#include <boost/process/detail/windows/close_out.hpp>
+#include <boost/process/detail/windows/null_in.hpp>
+#include <boost/process/detail/windows/null_out.hpp>
+#include <boost/process/detail/windows/file_in.hpp>
+#include <boost/process/detail/windows/file_out.hpp>
+#include <boost/process/detail/windows/pipe_in.hpp>
+#include <boost/process/detail/windows/pipe_out.hpp>
+#endif
+ +/** \file boost/process/io.hpp
+ *
+ * Header which provides the io properties. It provides the following properties:
+ *
+\xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::close">close</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::null">null</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_in">std_in</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_out">std_out</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::std_err">std_err</globalname>;
+ }
+}
+</programlisting>
+\endxmlonly
+ +\par File I/O
+ +The library allows full redirection of streams to files as shown below.
+ +\code{.cpp}
+boost::filesystem::path log = "my_log_file.txt";
+boost::filesystem::path input = "input.txt";
+boost::filesystem::path output = "output.txt";
+system("my_prog", std_out>output, std_in<input, std_err>log);
+\endcode
+ +\par Synchronous Pipe I/O
+ +Another way is to communicate through pipes.
+ +\code{.cpp}
+pstream str;
+child c("my_prog", std_out > str);
+ +int i;
+str >> i;
+\endcode
+ +Note that the pipe may also be used between several processes, like this:
+ +\code{.cpp}
+pipe p;
+child c1("nm", "a.out", std_out>p);
+child c2("c++filt", std_in<p);
+\endcode
+ +\par Asynchronous I/O
+ +Utilizing `boost.asio` asynchronous I/O is provided.
+ +\code
+boost::asio::io_service ios;
+std::future<std::string> output;
+system("ls", std_out > output, ios);
+ +auto res = fut.get();
+\endcode
+ +\note `boost/process/asnyc.hpp` must also be included for this to work.
+ +\par Closing
+ +Stream can be closed, so nothing can be read or written.
+ +\code{.cpp}
+system("foo", std_in.close());
+\endcode
+ +\par Null
+ +Streams can be redirected to null, which means, that written date will be
+discarded and read data will only contain `EOF`.
+ +\code{.cpp}
+system("b2", std_out > null);
+\endcode
+ + *
+ */
+ +namespace boost { namespace process { namespace detail {
+ + +template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
+template<typename T> using is_const_buffer =
+ std::integral_constant<bool,
+ std::is_same< boost::asio::const_buffer, T>::value |
+ std::is_base_of<boost::asio::const_buffer, T>::value
+ >;
+template<typename T> using is_mutable_buffer =
+ std::integral_constant<bool,
+ std::is_same< boost::asio::mutable_buffer, T>::value |
+ std::is_base_of<boost::asio::mutable_buffer, T>::value
+ >;
+ + +struct null_t {constexpr null_t() {}};
+struct close_t;
+ +template<class>
+struct std_in_
+{
+ constexpr std_in_() {}
+ + api::close_in close() const {return api::close_in(); }
+ api::close_in operator=(const close_t &) const {return api::close_in();}
+ api::close_in operator<(const close_t &) const {return api::close_in();}
+ + api::null_in null() const {return api::null_in();}
+ api::null_in operator=(const null_t &) const {return api::null_in();}
+ api::null_in operator<(const null_t &) const {return api::null_in();}
+ + api::file_in operator=(const boost::filesystem::path &p) const {return p;}
+ api::file_in operator=(const std::string & p) const {return p;}
+ api::file_in operator=(const std::wstring &p) const {return p;}
+ api::file_in operator=(const char * p) const {return p;}
+ api::file_in operator=(const wchar_t * p) const {return p;}
+ + api::file_in operator<(const boost::filesystem::path &p) const {return p;}
+ api::file_in operator<(const std::string &p) const {return p;}
+ api::file_in operator<(const std::wstring &p) const {return p;}
+ api::file_in operator<(const char*p) const {return p;}
+ api::file_in operator<(const wchar_t * p) const {return p;}
+ + api::file_in operator=(FILE * f) const {return f;}
+ api::file_in operator<(FILE * f) const {return f;}
+ + template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p) const {return p;}
+ template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p) const {return p;}
+ template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p) const {return p.pipe();}
+ + api::async_pipe_in operator=(async_pipe & p) const {return p;}
+ api::async_pipe_in operator<(async_pipe & p) const {return p;}
+ + template<typename T, typename = typename std::enable_if<
+ is_const_buffer<T>::value || is_mutable_buffer<T>::value
+ >::type>
+ api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
+ template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
+ api::async_in_buffer<T> operator=(T & buf) const {return buf;}
+ + template<typename T, typename = typename std::enable_if<
+ is_const_buffer<T>::value || is_mutable_buffer<T>::value
+ >::type>
+ api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
+ template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
+ api::async_in_buffer<T> operator<(T & buf) const {return buf;}
+ +};
+ +//-1 == empty.
+//1 == stdout
+//2 == stderr
+template<int p1, int p2 = -1>
+struct std_out_
+{
+ constexpr std_out_() {}
+ + api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); }
+ api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();}
+ api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();}
+ + api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();}
+ api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
+ api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
+ + api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
+ + api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
+ api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
+ + api::file_out<p1,p2> operator=(FILE * f) const {return f;}
+ api::file_out<p1,p2> operator>(FILE * f) const {return f;}
+ + template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p) const {return p;}
+ template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p) const {return p;}
+ template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
+ template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p) const {return p.pipe();}
+ + api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
+ api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
+ + api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
+ api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
+ api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
+ + api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
+ api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
+ api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
+ + api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
+ api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
+ api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
+ api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
+ + template<int pin, typename = typename std::enable_if<
+ (((p1 == 1) && (pin == 2)) ||
+ ((p1 == 2) && (pin == 1)))
+ && (p2 == -1)>::type>
+ constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
+ {
+ return std_out_<1, 2> ();
+ }
+ +};
+ +struct close_t
+{
+ constexpr close_t() {}
+ template<int T, int U>
+ api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
+};
+ + + +}
+///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams.
+constexpr boost::process::detail::close_t close;
+///This constant is a utility to redirect streams to the null-device.
+constexpr boost::process::detail::null_t null;
+ +/**
+This property allows to set the input stream for the child process.
+ +\section stdin_details Details
+ +\subsection stdin_file File Input
+ +The file I/O simple redirects the stream to a file, for which the possible types are
+ + - `boost::filesystem::path`
+ - `std::basic_string<char_type>`
+ - `const char_type*`
+ - `FILE*`
+ +with `char_type` being either `char` or `wchar_t`.
+ +FILE* is explicitly added, so the process can easily redirect the output stream
+of the child to another output stream of the process. That is:
+ +\code{.cpp}
+system("ls", std_in < stdin);
+\endcode
+ +\warning If the launching and the child process use the input, this leads to undefined behaviour.
+ +A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
+implementation not providing access to the handle.
+ +The valid expressions for this property are
+ +\code{.cpp}
+std_in < file;
+std_in = file;
+\endcode
+ +\subsection stdin_pipe Pipe Input
+ +As explained in the corresponding section, the boost.process library provides a
+@ref boost::process::async_pipe "async_pipe" class which can be
+used to communicate with child processes.
+ +\note Technically the @ref boost::process::async_pipe "async_pipe"
+works synchronous here, since no asio implementation is used by the library here.
+The async-operation will then however not end if the process is finished, since
+the pipe remains open. You can use the async_close function with on_exit to fix that.
+ +Valid expressions with pipes are these:
+ +\code{.cpp}
+std_in < pipe;
+std_in = pipe;
+\endcode
+ +Where the valid types for `pipe` are the following:
+ + - `basic_pipe`
+ - `async_pipe`
+ - `basic_opstream`
+ - `basic_pstream`
+ +Note that the pipe may also be used between several processes, like this:
+ +\code{.cpp}
+pipe p;
+child c1("nm", "a.out", std_out>p);
+child c2("c++filt", std_in<p);
+\endcode
+ +\subsection stdin_async_pipe Asynchronous Pipe Input
+ +Asynchronous Pipe I/O classifies communication which has automatically handling
+of the asynchronous operations by the process library. This means, that a pipe will be
+constructed, the async_read/-write will be automatically started, and that the
+end of the child process will also close the pipe.
+ +Valid types for pipe I/O are the following:
+ + - `boost::asio::const_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
+ - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
+ - `boost::asio::streambuf`
+ +Valid expressions with pipes are these:
+ +\code{.cpp}
+std_in < buffer;
+std_in = buffer;
+std_out > buffer;
+std_out = buffer;
+std_err > buffer;
+std_err = buffer;
+(std_out & std_err) > buffer;
+(std_out & std_err) = buffer;
+\endcode
+ +\note It is also possible to get a future for std_in, by chaining another `std::future<void>` onto it,
+so you can wait for the input to be completed. It looks like this:
+\code{.cpp}
+std::future<void> fut;
+boost::asio::io_service ios;
+std::string data;
+child c("prog", std_in < buffer(data) > fut, ios);
+fut.get();
+\endcode
+ + +\note `boost::asio::buffer` is also available in the `boost::process` namespace.
+ +\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_service` to be passed to the launching function.
+ + +\subsection stdin_close Close
+ +The input stream can be closed, so it cannot be read from. This will lead to an error when attempted.
+ +This can be achieved by the following syntax.
+ +\code{.cpp}
+std_in < close;
+std_in = close;
+std_in.close();
+\endcode
+ +\subsection stdin_null Null
+ +The input stream can be redirected to read from the null-device, which means that only `EOF` is read.
+ +The syntax to achieve that has the following variants:
+ +\code{.cpp}
+std_in < null;
+std_in = null;
+std_in.null();
+\endcode
+ +*/
+ +constexpr boost::process::detail::std_in_<void> std_in;
+ +/**
+This property allows to set the output stream for the child process.
+ +\note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly
+ +\note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`.
+ +\section stdout_details Details
+ +\subsection stdout_file File Input
+ +The file I/O simple redirects the stream to a file, for which the possible types are
+ + - `boost::filesystem::path`
+ - `std::basic_string<char_type>`
+ - `const char_type*`
+ - `FILE*`
+ +with `char_type` being either `char` or `wchar_t`.
+ +FILE* is explicitly added, so the process can easily redirect the output stream
+of the child to another output stream of the process. That is:
+ +\code{.cpp}
+system("ls", std_out < stdin);
+\endcode
+ +\warning If the launching and the child process use the input, this leads to undefined behaviour.
+ +A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
+implementation not providing access to the handle.
+ +The valid expressions for this property are
+ +\code{.cpp}
+std_out < file;
+std_out = file;
+\endcode
+ +\subsection stdout_pipe Pipe Output
+ +As explained in the corresponding section, the boost.process library provides a
+@ref boost::process::async_pipe "async_pipe" class which can be
+used to communicate with child processes.
+ +\note Technically the @ref boost::process::async_pipe "async_pipe"
+works like a synchronous pipe here, since no asio implementation is used by the library here.
+The asynchronous operation will then however not end if the process is finished, since
+the pipe remains open. You can use the async_close function with on_exit to fix that.
+ +Valid expressions with pipes are these:
+ +\code{.cpp}
+std_out > pipe;
+std_out = pipe;
+\endcode
+ +Where the valid types for `pipe` are the following:
+ + - `basic_pipe`
+ - `async_pipe`
+ - `basic_ipstream`
+ - `basic_pstream`
+ +Note that the pipe may also be used between several processes, like this:
+ +\code{.cpp}
+pipe p;
+child c1("nm", "a.out", std_out>p);
+child c2("c++filt", std_in<p);
+\endcode
+ +\subsection stdout_async_pipe Asynchronous Pipe Output
+ +Asynchronous Pipe I/O classifies communication which has automatically handling
+of the async operations by the process library. This means, that a pipe will be
+constructed, the async_read/-write will be automatically started, and that the
+end of the child process will also close the pipe.
+ +Valid types for pipe I/O are the following:
+ + - `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
+ - `boost::asio::streambuf`
+ - `std::future<std::vector<char>>`
+ - `std::future<std::string>`
+ +Valid expressions with pipes are these:
+ +\code{.cpp}
+std_out > buffer;
+std_out = buffer;
+std_err > buffer;
+std_err = buffer;
+(std_out & std_err) > buffer;
+(std_out & std_err) = buffer;
+\endcode
+ +\note `boost::asio::buffer` is also available in the `boost::process` namespace.
+ +\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_service` to be passed to the launching function.
+ + +\subsection stdout_close Close
+ +The out stream can be closed, so it cannot be write from.
+This will lead to an error when attempted.
+ +This can be achieved by the following syntax.
+ +\code{.cpp}
+std_out > close;
+std_out = close;
+std_out.close();
+\endcode
+ +\subsection stdout_null Null
+ +The output stream can be redirected to write to the null-device,
+which means that all output is discarded.
+ +The syntax to achieve that has the following variants:
+ +\code{.cpp}
+std_out > null;
+std_out = null;
+std_out.null();
+\endcode
+ +*/
+ +constexpr boost::process::detail::std_out_<1> std_out;
+/**This property allows setting the `stderr` stream. The semantic and syntax is the same as for
+ * \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly .
+ */
+constexpr boost::process::detail::std_out_<2> std_err;
+ +}}
+#endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */
diff --git a/boost/process/locale.hpp b/boost/process/locale.hpp new file mode 100644 index 0000000000..c8bcf4f9ea --- /dev/null +++ b/boost/process/locale.hpp @@ -0,0 +1,246 @@ +// 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_LOCALE_HPP_
+#define BOOST_PROCESS_LOCALE_HPP_
+ +#include <system_error>
+#include <boost/process/detail/config.hpp>
+ +#if defined(BOOST_WINDOWS_API)
+#include <boost/process/detail/windows/locale.hpp>
+# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
+|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+#include <codecvt>
+#endif
+ +#include <locale>
+ +namespace boost
+{
+namespace process
+{
+namespace detail
+{
+ +class codecvt_category_t : public std::error_category
+{
+public:
+ codecvt_category_t(){}
+ const char* name() const noexcept override {return "codecvt";}
+ std::string message(int ev) const override
+ {
+ std::string str;
+ switch (ev)
+ {
+ case std::codecvt_base::ok:
+ str = "ok";
+ break;
+ case std::codecvt_base::partial:
+ str = "partial";
+ break;
+ case std::codecvt_base::error:
+ str = "error";
+ break;
+ case std::codecvt_base::noconv:
+ str = "noconv";
+ break;
+ default:
+ str = "unknown error";
+ }
+ return str;
+ }
+};
+ +}
+ +///Internally used error cateory for code conversion.
+inline const std::error_category& codecvt_category()
+{
+ static const ::boost::process::detail::codecvt_category_t cat;
+ return cat;
+}
+ +namespace detail
+{
+//copied from boost.filesystem
+inline std::locale default_locale()
+{
+# if defined(BOOST_WINDOWS_API)
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new boost::process::detail::windows::windows_file_codecvt);
+# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
+|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
+ std::locale global_loc = std::locale();
+ return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
+# else // Other POSIX
+ // ISO C calls std::locale("") "the locale-specific native environment", and this
+ // locale is the default for many POSIX-based operating systems such as Linux.
+ return std::locale("");
+# endif
+}
+ +inline std::locale& process_locale()
+{
+ static std::locale loc(default_locale());
+ return loc;
+}
+ +}
+ +///The internally used type for code conversion.
+typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
+ +///Get a reference to the currently used code converter.
+inline const codecvt_type& codecvt()
+{
+ return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
+ detail::process_locale());
+}
+ +///Set the locale of the library.
+inline std::locale imbue(const std::locale& loc)
+{
+ std::locale temp(detail::process_locale());
+ detail::process_locale() = loc;
+ return temp;
+}
+ + +namespace detail
+{
+ +inline std::size_t convert(const char* from,
+ const char* from_end,
+ wchar_t* to, wchar_t* to_end,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
+ const char* from_next;
+ wchar_t* to_next;
+ + auto res = cvt.in(state, from, from_end, from_next,
+ to, to_end, to_next);
+ + if (res != std::codecvt_base::ok)
+ throw process_error(res, ::boost::process::codecvt_category(),
+ "boost::process codecvt to wchar_t");
+ + + return to_next - to;
+ +}
+ +inline std::size_t convert(const wchar_t* from,
+ const wchar_t* from_end,
+ char* to, char* to_end,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
+ const wchar_t* from_next;
+ char* to_next;
+ + std::codecvt_base::result res;
+ + if ((res=cvt.out(state, from, from_end, from_next,
+ to, to_end, to_next)) != std::codecvt_base::ok)
+ throw process_error(res, ::boost::process::codecvt_category(),
+ "boost::process codecvt to char");
+ + return to_next - to;
+}
+ +inline std::wstring convert(const std::string & st,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::wstring out(st.size() + 10, ' '); //just to be sure
+ auto sz = convert(st.c_str(), st.c_str() + st.size(),
+ &out.front(), &out.back(), cvt);
+ + out.resize(sz);
+ return out;
+}
+ +inline std::string convert(const std::wstring & st,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::string out(st.size() * 2, ' '); //just to be sure
+ auto sz = convert(st.c_str(), st.c_str() + st.size(),
+ &out.front(), &out.back(), cvt);
+ + out.resize(sz);
+ return out;
+}
+ +inline std::vector<wchar_t> convert(const std::vector<char> & st,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::vector<wchar_t> out(st.size() + 10); //just to be sure
+ auto sz = convert(st.data(), st.data() + st.size(),
+ &out.front(), &out.back(), cvt);
+ + out.resize(sz);
+ return out;
+}
+ +inline std::vector<char> convert(const std::vector<wchar_t> & st,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ std::vector<char> out(st.size() * 2); //just to be sure
+ auto sz = convert(st.data(), st.data() + st.size(),
+ &out.front(), &out.back(), cvt);
+ + out.resize(sz);
+ return out;
+}
+ + +inline std::wstring convert(const char *begin, const char* end,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ auto size = end-begin;
+ std::wstring out(size + 10, ' '); //just to be sure
+ using namespace std;
+ auto sz = convert(begin, end,
+ &out.front(), &out.back(), cvt);
+ out.resize(sz);
+ return out;
+}
+ +inline std::string convert(const wchar_t * begin, const wchar_t *end,
+ const ::boost::process::codecvt_type & cvt =
+ ::boost::process::codecvt())
+{
+ auto size = end-begin;
+ + std::string out(size * 2, ' '); //just to be sure
+ auto sz = convert(begin, end ,
+ &out.front(), &out.back(), cvt);
+ + out.resize(sz);
+ return out;
+}
+ + + + +}
+ + + +}
+}
+ + + + +#endif /* BOOST_PROCESS_LOCALE_HPP_ */
diff --git a/boost/process/pipe.hpp b/boost/process/pipe.hpp new file mode 100644 index 0000000000..8af776f966 --- /dev/null +++ b/boost/process/pipe.hpp @@ -0,0 +1,475 @@ +// 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_PIPE_HPP +#define BOOST_PROCESS_PIPE_HPP + +#include <boost/config.hpp> +#include <boost/process/detail/config.hpp> +#include <streambuf> +#include <istream> +#include <ostream> +#include <vector> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/basic_pipe.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/basic_pipe.hpp> +#endif + +namespace boost { namespace process { + +using ::boost::process::detail::api::basic_pipe; + +#if defined(BOOST_PROCESS_DOXYGEN) +/** Class implementation of a pipe. + * + */ +template<class CharT, class Traits = std::char_traits<CharT>> +class basic_pipe +{ +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; + + /// Default construct the pipe. Will be opened. + basic_pipe(); + + ///Construct a named pipe. + inline explicit basic_pipe(const std::string & name); + /** Copy construct the pipe. + * \note Duplicated the handles. + */ + inline basic_pipe(const basic_pipe& p); + /** Move construct the pipe. */ + basic_pipe(basic_pipe&& lhs); + /** Copy assign the pipe. + * \note Duplicated the handles. + */ + inline basic_pipe& operator=(const basic_pipe& p); + /** Move assign the pipe. */ + basic_pipe& operator=(basic_pipe&& lhs); + /** Destructor closes the handles. */ + ~basic_pipe(); + /** Get the native handle of the source. */ + native_handle native_source() const; + /** Get the native handle of the sink. */ + native_handle native_sink () const; + + /** Assign a new value to the source */ + void assign_source(native_handle h); + /** Assign a new value to the sink */ + void assign_sink (native_handle h); + + + ///Write data to the pipe. + int_type write(const char_type * data, int_type count); + ///Read data from the pipe. + int_type read(char_type * data, int_type count); + ///Check if the pipe is open. + bool is_open(); + ///Close the pipe + void close(); +}; + +#endif + + + +typedef basic_pipe<char> pipe; +typedef basic_pipe<wchar_t> wpipe; + + +/** Implementation of the stream buffer for a pipe. + */ +template< + class CharT, + class Traits = std::char_traits<CharT> +> +struct basic_pipebuf : std::basic_streambuf<CharT, Traits> +{ + typedef basic_pipe<CharT, Traits> pipe_type; + + 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 ; + + constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE; + + ///Default constructor, will also construct the pipe. + basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size) + { + this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); + this->setp(_write.data(), _write.data() + _write.size()); + } + ///Copy Constructor. + basic_pipebuf(const basic_pipebuf & ) = default; + ///Move Constructor + basic_pipebuf(basic_pipebuf && ) = default; + + ///Move construct from a pipe. + basic_pipebuf(pipe_type && p) : _pipe(std::move(p)), + _write(default_buffer_size), + _read(default_buffer_size) + { + this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); + this->setp(_write.data(), _write.data() + _write.size()); + } + ///Construct from a pipe. + basic_pipebuf(const pipe_type & p) : _pipe(p), + _write(default_buffer_size), + _read(default_buffer_size) + { + this->setg(_read.data(), _read.data()+ 128, _read.data() + 128); + this->setp(_write.data(), _write.data() + _write.size()); + } + ///Copy assign. + basic_pipebuf& operator=(const basic_pipebuf & ) = delete; + ///Move assign. + basic_pipebuf& operator=(basic_pipebuf && ) = default; + ///Move assign a pipe. + basic_pipebuf& operator=(pipe_type && p) + { + _pipe = std::move(p); + return *this; + } + ///Copy assign a pipe. + basic_pipebuf& operator=(const pipe_type & p) + { + _pipe = p; + return *this; + } + ///Writes characters to the associated output sequence from the put area + int_type overflow(int_type ch = traits_type::eof()) override + { + if ((ch != traits_type::eof()) && _pipe.is_open()) + { + if (this->pptr() == this->epptr()) + { + bool wr = this->_write_impl(); + *this->pptr() = ch; + this->pbump(1); + if (wr) + return ch; + } + else + { + *this->pptr() = ch; + this->pbump(1); + if (this->_write_impl()) + return ch; + } + } + return traits_type::eof(); + } + ///Synchronizes the buffers with the associated character sequence + int sync() override { return this->_write_impl() ? 0 : -1; } + + ///Reads characters from the associated input sequence to the get area + int_type underflow() override + { + if (!_pipe.is_open()) + return traits_type::eof(); + + if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer + this->setg(_read.data(), _read.data()+ 10, _read.data() + 10); + + + auto len = &_read.back() - this->egptr() ; + auto res = _pipe.read( + this->egptr(), + static_cast<typename pipe_type::int_type>(len)); + if (res == 0) + return traits_type::eof(); + + this->setg(this->eback(), this->gptr(), this->egptr() + res); + auto val = *this->gptr(); + + return traits_type::to_int_type(val); + } + + + ///Set the pipe of the streambuf. + void pipe(pipe_type&& p) {_pipe = std::move(p); } + ///Set the pipe of the streambuf. + void pipe(const pipe_type& p) {_pipe = p; } + ///Get a reference to the pipe. + pipe_type & pipe() & {return _pipe;} + ///Get a const reference to the pipe. + const pipe_type &pipe() const & {return _pipe;} + ///Get a rvalue reference to the pipe. Qualified as rvalue. + pipe_type && pipe() && {return std::move(_pipe);} +private: + pipe_type _pipe; + std::vector<char_type> _write; + std::vector<char_type> _read; + + bool _write_impl() + { + if (!_pipe.is_open()) + return false; + + auto base = this->pbase(); + auto wrt = _pipe.write(base, + static_cast<typename pipe_type::int_type>(this->pptr() - base)); + std::ptrdiff_t diff = this->pptr() - base; + + if (wrt < diff) + std::move(base + wrt, base + diff, base); + else if (wrt == 0) //broken pipe + return false; + + this->pbump(-wrt); + + return true; + } +}; + +typedef basic_pipebuf<char> pipebuf; +typedef basic_pipebuf<wchar_t> wpipebuf; + +/** Implementation of a reading pipe stream. + * + */ +template< + class CharT, + class Traits = std::char_traits<CharT> +> +class basic_ipstream : public std::basic_istream<CharT, Traits> +{ + basic_pipebuf<CharT, Traits> _buf; +public: + + typedef basic_pipe<CharT, Traits> pipe_type; + + 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 ; + + ///Get access to the underlying stream_buf + basic_pipebuf<CharT, Traits>* rdbuf() const {return _buf;}; + + ///Default constructor. + basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr) + { + std::basic_istream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy constructor. + basic_ipstream(const basic_ipstream & ) = delete; + ///Move constructor. + basic_ipstream(basic_ipstream && ) = default; + + ///Move construct from a pipe. + basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p)) + { + std::basic_istream<CharT, Traits>::rdbuf(&_buf); + } + + ///Copy construct from a pipe. + basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p) + { + std::basic_istream<CharT, Traits>::rdbuf(&_buf); + } + + ///Copy assignment. + basic_ipstream& operator=(const basic_ipstream & ) = delete; + ///Move assignment + basic_ipstream& operator=(basic_ipstream && ) = default; + ///Move assignment of a pipe. + basic_ipstream& operator=(pipe_type && p) + { + _buf = std::move(p); + return *this; + } + ///Copy assignment of a pipe. + basic_ipstream& operator=(const pipe_type & p) + { + _buf = p; + return *this; + } + ///Set the pipe of the streambuf. + void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } + ///Set the pipe of the streambuf. + void pipe(const pipe_type& p) {_buf.pipe(p); } + ///Get a reference to the pipe. + pipe_type & pipe() & {return _buf.pipe();} + ///Get a const reference to the pipe. + const pipe_type &pipe() const & {return _buf.pipe();} + ///Get a rvalue reference to the pipe. Qualified as rvalue. + pipe_type && pipe() && {return std::move(_buf).pipe();} +}; + +typedef basic_ipstream<char> ipstream; +typedef basic_ipstream<wchar_t> wipstream; + +/** Implementation of a write pipe stream. + * + */ +template< + class CharT, + class Traits = std::char_traits<CharT> +> +class basic_opstream : public std::basic_ostream<CharT, Traits> +{ + basic_pipebuf<CharT, Traits> _buf; +public: + typedef basic_pipe<CharT, Traits> pipe_type; + + 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 ; + + + ///Get access to the underlying stream_buf + basic_pipebuf<CharT, Traits>* rdbuf() const {return _buf;}; + + ///Default constructor. + basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr) + { + std::basic_ostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy constructor. + basic_opstream(const basic_opstream & ) = delete; + ///Move constructor. + basic_opstream(basic_opstream && ) = default; + + ///Move construct from a pipe. + basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p)) + { + std::basic_ostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy construct from a pipe. + basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p) + { + std::basic_ostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy assignment. + basic_opstream& operator=(const basic_opstream & ) = delete; + ///Move assignment + basic_opstream& operator=(basic_opstream && ) = default; + ///Move assignment of a pipe. + basic_opstream& operator=(pipe_type && p) + { + _buf = std::move(p); + return *this; + } + ///Copy assignment of a pipe. + basic_opstream& operator=(const pipe_type & p) + { + _buf = p; + return *this; + } + ///Set the pipe of the streambuf. + void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } + ///Set the pipe of the streambuf. + void pipe(const pipe_type& p) {_buf.pipe(p); } + ///Get a reference to the pipe. + pipe_type & pipe() & {return _buf.pipe();} + ///Get a const reference to the pipe. + const pipe_type &pipe() const & {return _buf.pipe();} + ///Get a rvalue reference to the pipe. Qualified as rvalue. + pipe_type && pipe() && {return std::move(_buf).pipe();} +}; + +typedef basic_opstream<char> opstream; +typedef basic_opstream<wchar_t> wopstream; + + +/** Implementation of a read-write pipe stream. + * + */ +template< + class CharT, + class Traits = std::char_traits<CharT> +> +class basic_pstream : public std::basic_iostream<CharT, Traits> +{ + basic_pipebuf<CharT, Traits> _buf; +public: + typedef basic_pipe<CharT, Traits> pipe_type; + + 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 ; + + + ///Get access to the underlying stream_buf + basic_pipebuf<CharT, Traits>* rdbuf() const {return _buf;}; + + ///Default constructor. + basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr) + { + std::basic_iostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy constructor. + basic_pstream(const basic_pstream & ) = delete; + ///Move constructor. + basic_pstream(basic_pstream && ) = default; + + ///Move construct from a pipe. + basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p)) + { + std::basic_iostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy construct from a pipe. + basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p) + { + std::basic_iostream<CharT, Traits>::rdbuf(&_buf); + }; + ///Copy assignment. + basic_pstream& operator=(const basic_pstream & ) = delete; + ///Move assignment + basic_pstream& operator=(basic_pstream && ) = default; + ///Move assignment of a pipe. + basic_pstream& operator=(pipe_type && p) + { + _buf = std::move(p); + return *this; + } + ///Copy assignment of a pipe. + basic_pstream& operator=(const pipe_type & p) + { + _buf = p; + return *this; + } + ///Set the pipe of the streambuf. + void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); } + ///Set the pipe of the streambuf. + void pipe(const pipe_type& p) {_buf.pipe(p); } + ///Get a reference to the pipe. + pipe_type & pipe() & {return _buf.pipe();} + ///Get a const reference to the pipe. + const pipe_type &pipe() const & {return _buf.pipe();} + ///Get a rvalue reference to the pipe. Qualified as rvalue. + pipe_type && pipe() && {return std::move(_buf).pipe();} +}; + +typedef basic_pstream<char> pstream; +typedef basic_pstream<wchar_t> wpstream; + + + +}} + + + +#endif diff --git a/boost/process/posix.hpp b/boost/process/posix.hpp new file mode 100644 index 0000000000..909837b8aa --- /dev/null +++ b/boost/process/posix.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_POSIX_HPP_ +#define BOOST_PROCESS_POSIX_HPP_ + +#include <boost/process/detail/posix/fd.hpp> +#include <boost/process/detail/posix/handler.hpp> +#include <boost/process/detail/posix/use_vfork.hpp> +#include <boost/process/detail/posix/signal.hpp> + + +/** \file boost/process/posix.hpp + * + * Header which provides the posix extensions. +\xmlonly +<programlisting> +namespace boost { + namespace process { + namespace posix { + <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::fd">fd</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::sig">sig</globalname>; + <emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::use_vfork">use_vfork</globalname>; + } + } +} +</programlisting> + * \endxmlonly + * \warning Only available on posix. See the documentation of [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), + * [execve](http://pubs.opengroup.org/onlinepubs/009695399/functions/execve.html) and + * [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html). + * + */ + +namespace boost { namespace process { + +///Namespace containing the posix exensions. +namespace posix { + +/** This property lets you modify file-descriptors other than the standard ones (0,1,2). + * + * It provides the functions `bind`, which implements [dup2](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html) + * and [close](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html). + * + * Close can also be called with a range of file-descriptors to be closed. + * + */ +constexpr ::boost::process::detail::posix::fd_ fd; + +/** This property lets you modify the handling of `SIGCHLD` for this call. It will be reset afterwards. + +It can be set to default, by the expression `sig.dfl()`, set to ignore with `sig.ign()` or +assigned a custom handler. A custom handler must have the type `sighandler_t`and can be assigned with the following syntax: + +\code{.cpp} +sig = handler; +sig(handler); +\endcode + +\warning @ref spawn will automatically use `sig.ign()`, which will override if you pass a custom handler. + */ +constexpr ::boost::process::detail::posix::sig_ sig; +/** This property will replace the usage of [fork](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html) by [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html). + \note `vfork` is no longer an official part of the posix standard. + + */ +constexpr ::boost::process::detail::posix::use_vfork_ use_vfork; + + +using ::boost::process::detail::posix::sighandler_t; + +}}} + +#endif /* BOOST_PROCESS_POSIX_HPP_ */ diff --git a/boost/process/search_path.hpp b/boost/process/search_path.hpp new file mode 100644 index 0000000000..1c38a61608 --- /dev/null +++ b/boost/process/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) + +/** + * \file boost/process/search_path.hpp + * + * Defines a function to search for an executable in path. + */ + +#ifndef BOOST_PROCESS_SEARCH_PATH_HPP +#define BOOST_PROCESS_SEARCH_PATH_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/environment.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/search_path.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/search_path.hpp> +#endif + + +namespace boost { namespace process { + +/** + * Searches for an executable in path. + * + * filename must be a basename including the file extension. + * It must not include any directory separators (like a slash). + * On Windows the file extension may be omitted. The function + * will then try the various file extensions for executables on + * Windows to find filename. + * + * \param filename The base of the filename to find + * + * \param path the set of paths so search, defaults to "PATH" environment variable. + * + * \returns the absolute path to the executable filename or an + * empty string if filename isn't found + */ +inline boost::filesystem::path search_path(const boost::filesystem::path &filename, + const std::vector<boost::filesystem::path> path = ::boost::this_process::path()) +{ + return ::boost::process::detail::api::search_path(filename, path); +} +}} + +#endif diff --git a/boost/process/shell.hpp b/boost/process/shell.hpp new file mode 100644 index 0000000000..64314a688d --- /dev/null +++ b/boost/process/shell.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 +// 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_SHELL_PATH_HPP +#define BOOST_PROCESS_SHELL_PATH_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/traits/wchar_t.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/shell_path.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/shell_path.hpp> +#endif + +/** \file boost/process/shell.hpp + * + * Header which provides the shell property. This provides the + * property to launch a process through the system shell. + * It also allows the user to obtain the shell-path via shell(). +\xmlonly +<programlisting> +namespace boost { + namespace process { + <emphasis>unspecified</emphasis> <globalname alt="boost::process::shell">shell</globalname>; + } +} +</programlisting> +\endxmlonly + + */ + +namespace boost { namespace process { namespace detail { + + +struct shell_ +{ + constexpr shell_() {} + + boost::filesystem::path operator()() const + { + return boost::process::detail::api::shell_path(); + } + boost::filesystem::path operator()(std::error_code & ec) const noexcept + { + return boost::process::detail::api::shell_path(ec); + } +}; + +template<> +struct is_wchar_t<shell_> : is_wchar_t<boost::filesystem::path> +{ +}; + +} +/** +The shell property enables to launch a program through the shell of the system. + +\code{.cpp} +system("gcc", shell); +\endcode + +The shell argument goes without any expression. The operator() is overloaded, to +obtain the path of the system shell. + +\code{.cpp} +auto shell_cmd = shell(); +//avoid exceptions +std::error_code ec; +shell_cmd = shell(ec); +\endcode + +\attention Launching through the shell will NOT provide proper error handling, i.e. +you will get an error via the return code. + +\attention Executing shell commands that incorporate unsanitized input from an untrusted source makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of `shell` is strongly discouraged in cases where the command string is constructed from external input: + +*/ +constexpr ::boost::process::detail::shell_ shell; + +}} + + + +#endif diff --git a/boost/process/spawn.hpp b/boost/process/spawn.hpp new file mode 100644 index 0000000000..fb1e3594b1 --- /dev/null +++ b/boost/process/spawn.hpp @@ -0,0 +1,69 @@ +// 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/spawn.hpp + * + * Defines the spawn function. + */ + +#ifndef BOOST_PROCESS_SPAWN_HPP +#define BOOST_PROCESS_SPAWN_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/child_decl.hpp> +#include <boost/process/detail/execute_impl.hpp> +#include <boost/process/detail/async_handler.hpp> + +#if defined(BOOST_POSIX_API) +#include <boost/process/posix.hpp> +#endif + +namespace boost { + +namespace process { + +namespace detail { + +} + +/** Launch a process and detach it. Returns no handle. + +This function starts a process and immediately detaches it. It thereby prevents the system from creating a zombie process, +but will also cause the system to be unable to wait for the child to exit. + +\note This will set `SIGCHLD` to `SIGIGN` on posix. + +\warning This function does not allow asynchronous operations, since it cannot wait for the end of the process. +It will fail to compile if a reference to `boost::asio::io_service` is passed. + + */ +template<typename ...Args> +inline void spawn(Args && ...args) +{ + typedef typename ::boost::process::detail::has_async_handler<Args...>::type + has_async; + + + static_assert( + !has_async::value, + "Spawn cannot wait for exit, so async properties cannot be used"); + + auto c = ::boost::process::detail::execute_impl( +#if defined(BOOST_POSIX_API) + ::boost::process::posix::sig.ign(), +#endif + std::forward<Args>(args)...); + c.detach(); +} + +}} +#endif + diff --git a/boost/process/start_dir.hpp b/boost/process/start_dir.hpp new file mode 100644 index 0000000000..50a246f4b8 --- /dev/null +++ b/boost/process/start_dir.hpp @@ -0,0 +1,110 @@ +// 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_START_IN_DIR_HPP
+#define BOOST_PROCESS_START_IN_DIR_HPP
+ +#include <boost/process/detail/config.hpp>
+#include <boost/process/detail/handler.hpp>
+#include <boost/process/locale.hpp>
+ +#if defined (BOOST_POSIX_API)
+#include <boost/process/detail/posix/start_dir.hpp>
+#elif defined (BOOST_WINDOWS_API)
+#include <boost/process/detail/windows/start_dir.hpp>
+#endif
+ +#include <boost/process/detail/config.hpp>
+#include <string>
+#include <boost/filesystem/path.hpp>
+ +/** \file boost/process/start_dir.hpp
+ *
+Header which provides the start_dir property, which allows to set the directory
+the process shall be started in.
+\xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::start_dir">start_dir</globalname>;
+ }
+}
+</programlisting>
+\endxmlonly
+ + */
+ +namespace boost { namespace process { namespace detail {
+ +struct start_dir_
+{
+ constexpr start_dir_() {};
+ + template<typename Char>
+ api::start_dir_init<Char> operator()(const std::basic_string<Char> & st) const {return {st}; }
+ template<typename Char>
+ api::start_dir_init<Char> operator()(std::basic_string<Char> && s) const {return {std::move(s)}; }
+ template<typename Char>
+ api::start_dir_init<Char> operator()(const Char* s) const {return {s}; }
+ api::start_dir_init<typename boost::filesystem::path::value_type>
+ operator()(const boost::filesystem::path & st) const {return {st.native()}; }
+ + template<typename Char>
+ api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; }
+ template<typename Char>
+ api::start_dir_init<Char> operator= (std::basic_string<Char> && s) const {return {std::move(s)}; }
+ template<typename Char>
+ api::start_dir_init<Char> operator= (const Char* s) const {return {s}; }
+ api::start_dir_init<typename boost::filesystem::path::value_type>
+ operator= (const boost::filesystem::path & st) const {return {st.native()}; }
+ +};
+ +template<> struct is_wchar_t<api::start_dir_init<wchar_t>> : std::true_type {};
+ +template<>
+struct char_converter<char, api::start_dir_init<wchar_t>>
+{
+ static api::start_dir_init<char> conv(const api::start_dir_init<wchar_t> & in)
+ {
+ return api::start_dir_init<char>{::boost::process::detail::convert(in.str())};
+ }
+};
+ +template<>
+struct char_converter<wchar_t, api::start_dir_init<char>>
+{
+ static api::start_dir_init<wchar_t> conv(const api::start_dir_init<char> & in)
+ {
+ return api::start_dir_init<wchar_t>{::boost::process::detail::convert(in.str())};
+ }
+};
+ +}
+ +/**
+ +To set the start dir, the `start_dir` property is provided.
+ +The valid operations are the following:
+ +\code{.cpp}
+start_dir=path
+start_dir(path)
+\endcode
+ +It can be used with `std::string`, `std::wstring` and `boost::filesystem::path`.
+ + + */
+constexpr ::boost::process::detail::start_dir_ start_dir;
+ +}}
+ +#endif
diff --git a/boost/process/system.hpp b/boost/process/system.hpp new file mode 100644 index 0000000000..bdcac88713 --- /dev/null +++ b/boost/process/system.hpp @@ -0,0 +1,154 @@ +// 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/system.hpp + * + * Defines a system function. + */ + +#ifndef BOOST_PROCESS_SYSTEM_HPP +#define BOOST_PROCESS_SYSTEM_HPP + +#include <boost/process/detail/config.hpp> +#include <boost/process/detail/on_exit.hpp> +#include <boost/process/child.hpp> +#include <boost/process/detail/async_handler.hpp> +#include <boost/process/detail/execute_impl.hpp> +#include <type_traits> +#include <mutex> +#include <condition_variable> + +#if defined(BOOST_POSIX_API) +#include <boost/process/posix.hpp> +#endif + +namespace boost { + +namespace process { + +namespace detail +{ + +struct system_impl_success_check : handler +{ + bool succeeded = false; + + template<typename Exec> + void on_success(Exec &) { succeeded = true; } +}; + +template<typename IoService, typename ...Args> +inline int system_impl( + std::true_type, /*needs ios*/ + std::true_type, /*has io_service*/ + Args && ...args) +{ + IoService & ios = ::boost::process::detail::get_io_service_var(args...); + + system_impl_success_check check; + + std::atomic_bool exited{false}; + + child c(std::forward<Args>(args)..., + check, + ::boost::process::on_exit( + [&](int, const std::error_code&) + { + ios.post([&]{exited.store(true);}); + })); + if (!c.valid() || !check.succeeded) + return -1; + + while (!exited.load()) + ios.poll(); + + return c.exit_code(); +} + +template<typename IoService, typename ...Args> +inline int system_impl( + std::true_type, /*needs ios */ + std::false_type, /*has io_service*/ + Args && ...args) +{ + IoService ios; + child c(ios, std::forward<Args>(args)...); + if (!c.valid()) + return -1; + + ios.run(); + return c.exit_code(); +} + + +template<typename IoService, typename ...Args> +inline int system_impl( + std::false_type, /*needs ios*/ + std::true_type, /*has io_service*/ + Args && ...args) +{ + child c(std::forward<Args>(args)...); + if (!c.valid()) + return -1; + c.wait(); + return c.exit_code(); +} + +template<typename IoService, typename ...Args> +inline int system_impl( + std::false_type, /*has async */ + std::false_type, /*has io_service*/ + Args && ...args) +{ + child c(std::forward<Args>(args)... +#if defined(BOOST_POSIX_API) + ,::boost::process::posix::sig.dfl() +#endif + ); + if (!c.valid()) + return -1; + c.wait(); + return c.exit_code(); +} + +} + +/** Launches a process and waits for its exit. +It works as std::system, though it allows +all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code. + +\code{.cpp} +int ret = system("ls"); +\endcode + +\attention Using this function with synchronous pipes leads to many potential deadlocks. + +When using this function with an asynchronous properties and NOT passing an io_service object, +the system function will create one and run it. When the io_service is passed to the function, +the system function will check if it is active, and call the io_service::run function if not. + +*/ +template<typename ...Args> +inline int system(Args && ...args) +{ + typedef typename ::boost::process::detail::needs_io_service<Args...>::type + need_ios; + typedef typename ::boost::process::detail::has_io_service<Args...>::type + has_ios; + return ::boost::process::detail::system_impl<boost::asio::io_service>( + need_ios(), has_ios(), + std::forward<Args>(args)...); +} + + +}} +#endif + diff --git a/boost/process/windows.hpp b/boost/process/windows.hpp new file mode 100644 index 0000000000..3bc97a26aa --- /dev/null +++ b/boost/process/windows.hpp @@ -0,0 +1,58 @@ +// 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_HPP_
+#define BOOST_PROCESS_WINDOWS_HPP_
+ +#include <boost/process/detail/windows/show_window.hpp>
+ +/** \file boost/process/windows.hpp
+ *
+ * Header which provides the windows extensions.
+ +\xmlonly
+<programlisting>
+namespace boost {
+ namespace process {
+ namespace windows {
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::hide">hide</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::maximized">maximized</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::minimized">minimized</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::minimized_not_active">minimized_not_active</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::not_active">not_active</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show">show</globalname>;
+ <emphasis>unspecified</emphasis> <globalname alt="boost::process::windows::show_normal">show_normal</globalname>;
+ }
+ }
+}
+</programlisting>
+ * \endxmlonly
+ * \warning Only available on windows.
+ * See the parameter documentation of [ShowWindow](https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548.aspx) for more details.
+ */
+ +namespace boost { namespace process {
+ +///Namespace containing the windows exensions.
+namespace windows {
+ +///Hides the window and activates another window.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_HIDE_ > hide;
+///Activates the window and displays it as a maximized window.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWMAXIMIZED_ > maximized;
+///Activates the window and displays it as a minimized window.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWMINIMIZED_ > minimized;
+///Displays the window as a minimized window. This value is similar to `minimized`, except the window is not activated.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWMINNOACTIVE_> minimized_not_active;
+///Displays a window in its most recent size and position. This value is similar to show_normal`, except that the window is not activated.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWNOACTIVATE_ > not_active;
+///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWNORMAL_ > show;
+///Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
+constexpr ::boost::process::detail::windows::show_window<::boost::detail::winapi::SW_SHOWNORMAL_ > show_normal;
+ + +}}}
+ +#endif /* BOOST_PROCESS_WINDOWS_HPP_ */
|