diff --git a/CMakeLists.txt b/CMakeLists.txt index c0c1bfef9..01c1bc21c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,12 +7,30 @@ cmake_minimum_required(VERSION 3.5...3.16) project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) -add_library(boost_process INTERFACE) +add_library(boost_process + src/detail/environment_posix.cpp + src/detail/environment_win.cpp + src/detail/last_error.cpp + src/detail/process_handle_windows.cpp + src/detail/throw_error.cpp + src/detail/utf8.cpp + src/ext/cmd.cpp + src/ext/cwd.cpp + src/ext/env.cpp + src/ext/exe.cpp + src/ext/proc_info.cpp + src/posix/close_handles.cpp + src/windows/default_launcher.cpp + src/environment.cpp + src/error.cpp + src/pid.cpp + src/shell.cpp) + add_library(Boost::process ALIAS boost_process) -target_include_directories(boost_process INTERFACE include) +target_include_directories(boost_process PUBLIC include) target_link_libraries(boost_process - INTERFACE + PUBLIC Boost::algorithm Boost::asio Boost::config @@ -28,6 +46,16 @@ target_link_libraries(boost_process Boost::winapi ) +target_compile_definitions(boost_process + PRIVATE BOOST_PROCESS_SOURCE=1 +) + +if(BUILD_SHARED_LIBS) + target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_DYN_LINK) +else() + target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_STATIC_LINK) +endif() + if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") add_subdirectory(test) diff --git a/build/Jamfile b/build/Jamfile new file mode 100644 index 000000000..fe98df690 --- /dev/null +++ b/build/Jamfile @@ -0,0 +1,49 @@ +# Copyright (c) 2024 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) + +import os ; +import feature ; +import ../../config/checks/config : requires ; + +project : requirements + BOOST_ASIO_NO_DEPRECATED + msvc:_SCL_SECURE_NO_WARNINGS + msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj + windows:WIN32_LEAN_AND_MEAN + linux:-lpthread + : source-location ../src +; + +alias process_sources + : detail/environment_posix.cpp + detail/environment_win.cpp + detail/last_error.cpp + detail/process_handle_windows.cpp + detail/throw_error.cpp + detail/utf8.cpp + ext/cmd.cpp + ext/cwd.cpp + ext/env.cpp + ext/exe.cpp + ext/proc_info.cpp + posix/close_handles.cpp + windows/default_launcher.cpp + environment.cpp + error.cpp + pid.cpp + shell.cpp + ; + +lib boost_process + : process_sources + : requirements BOOST_PROCESS_SOURCE=1 + shared:BOOST_PROCESS_DYN_LINK=1 + : usage-requirements + shared:BOOST_PROCESS_DYN_LINK=1 + + ; + +boost-install boost_process ; \ No newline at end of file diff --git a/doc/Jamfile.jam b/doc/Jamfile.jam index 15ff339dd..9700609ce 100644 --- a/doc/Jamfile.jam +++ b/doc/Jamfile.jam @@ -14,25 +14,28 @@ using doxygen ; local images = [ glob images/*.svg ] ; install images : $(images) : html/boost_process ; -install images_glob : $(images) : $(BOOST_ROOT)/doc/html/boost_process ; +install images_glob : $(images) : $(BOOST_ROOT)/doc/html/boost_process ; import type ; type.register XMLPROCESSWORKAROUND : : XML ; import generators ; generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ; -xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ; -xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ; +xmlprocessworkaround posix_pseudocode : v1/posix_pseudocode.xml ; +xmlprocessworkaround windows_pseudocode : v1/windows_pseudocode.xml ; path-constant INCLUDES : ../../.. ; -doxygen autodoc +doxygen reference_v1 : - $(INCLUDES)/boost/process.hpp - [ glob $(INCLUDES)/boost/process/*.hpp ] + $(INCLUDES)/boost/process/v1.hpp + [ glob $(INCLUDES)/boost/process/v1/*.hpp ] : EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE - PREDEFINED=BOOST_PROCESS_DOXYGEN + "PREDEFINED=\\ + BOOST_PROCESS_DOXYGEN=1 \\ + BOOST_PROCESS_V1_INLINE= + " HIDE_UNDOC_CLASSES=YES HIDE_UNDOC_MEMBERS=YES EXAMPLE_PATH=. @@ -67,6 +70,7 @@ doxygen reference_v2 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\ BOOST_CONSTEXPR=constexpr \\ BOOST_CXX14_CONSTEXPR=constexpr \\ + BOOST_PROCESS_V2_INLINE= \\ BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]] " reference_v2 @@ -84,7 +88,7 @@ boostbook standalone : process.qbk : - autodoc + reference_v1 reference_v2 images images_glob diff --git a/doc/posix_pseudocode.xml b/doc/posix_pseudocode.xml deleted file mode 100644 index 5ba3d8536..000000000 --- a/doc/posix_pseudocode.xml +++ /dev/null @@ -1,60 +0,0 @@ - - -for (auto & s : seq) - s.on_setup(*this); - -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} - -pid = fork() -on_setup(*this); - -if (pid == -1) //fork error -{ - set_error(get_last_error()); - for (auto & s : seq) - s.on_fork_error(*this, error()); - for (auto & s : seq) - s.on_error(*this, error()); - return child() -} -else if (pid == 0) //child process -{ - for (auto & s : seq) - s.on_exec_setup(*this); - execve(exe, cmd_line, env); - auto ec = get_last_error(); - for (auto & s : seq) - s.on_exec_error(*this); - - unspecified();//here the error is sent to the father process internally - - std::exit(EXIT_FAILURE); - return child(); //for C++ compliance -} - -child c(pid, exit_code); - -unspecified();//here, we read the error from the child process - -if (error()) - for (auto & s : seq) - s.on_error(*this, error()); -else - for (auto & s : seq) - s.on_success(*this); - -//now we check again, because an on_success handler might've errored. -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -else - return c; - \ No newline at end of file diff --git a/doc/process.qbk b/doc/process.qbk index 6dbfa57ad..bf3b3b802 100644 --- a/doc/process.qbk +++ b/doc/process.qbk @@ -11,14 +11,8 @@ ] ] -[note [link process.v2 Process V2] is available as experimental] +[note Process v1 will be deprecated in the future. Use v2 for new projects.] -[include introduction.qbk] -[include concepts.qbk] -[include tutorial.qbk] -[include design.qbk] -[include extend.qbk] -[include faq.qbk] -[xinclude autodoc.xml] +[include v1.qbk] +[include v2.qbk] [include acknowledgements.qbk] -[include v2.qbk] \ No newline at end of file diff --git a/doc/v1.qbk b/doc/v1.qbk new file mode 100644 index 000000000..85552bc8f --- /dev/null +++ b/doc/v1.qbk @@ -0,0 +1,11 @@ +[section:v1 Process V1] + +[include v1/introduction.qbk] +[include v1/concepts.qbk] +[include v1/tutorial.qbk] +[include v1/design.qbk] +[include v1/extend.qbk] +[include v1/faq.qbk] +[xinclude reference_v2.xml] + +[endsect] diff --git a/doc/concepts.qbk b/doc/v1/concepts.qbk similarity index 100% rename from doc/concepts.qbk rename to doc/v1/concepts.qbk diff --git a/doc/design.qbk b/doc/v1/design.qbk similarity index 97% rename from doc/design.qbk rename to doc/v1/design.qbk index 2611c29dd..0dd49f16e 100644 --- a/doc/design.qbk +++ b/doc/v1/design.qbk @@ -75,9 +75,9 @@ but the one of the launching process, not the one passed to the child process.] The simplest form to extend functionality is to provide another handler, which will be called on the respective events on process launching. The names are: -*`boost::process::on_setup` -*`boost::process::on_error` -*`boost::process::on_success` +*`boost::process::v1::on_setup` +*`boost::process::v1::on_error` +*`boost::process::v1::on_success` As an example: diff --git a/doc/extend.qbk b/doc/v1/extend.qbk similarity index 73% rename from doc/extend.qbk rename to doc/v1/extend.qbk index fad4db545..dfe4f8517 100644 --- a/doc/extend.qbk +++ b/doc/v1/extend.qbk @@ -1,14 +1,14 @@ -[def __on_exit__ [globalref boost::process::on_exit on_exit]] -[def __on_success__ [globalref boost::process::extend::on_success ex::on_success]] -[def __child__ [classref boost::process::child child]] -[def __handler__ [classref boost::process::extend::handler handler]] -[def __on_success__ [memberref boost::process::extend::handler::on_success on_success]] -[def __posix_executor__ [classref boost::process::extend::posix_executor ex::posix_executor]] -[def __windows_executor__ [classref boost::process::extend::windows_executor ex::windows_executor]] +[def __on_exit__ [globalref boost::process::v1::on_exit on_exit]] +[def __on_success__ [globalref boost::process::v1::extend::on_success ex::on_success]] +[def __child__ [classref boost::process::v1::child child]] +[def __handler__ [classref boost::process::v1::extend::handler handler]] +[def __on_success__ [memberref boost::process::v1::extend::handler::on_success on_success]] +[def __posix_executor__ [classref boost::process::v1::extend::posix_executor ex::posix_executor]] +[def __windows_executor__ [classref boost::process::v1::extend::windows_executor ex::windows_executor]] [def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]] -[def __require_io_context__ [classref boost::process::extend::require_io_context ex::require_io_context]] -[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]] -[def __get_io_context__ [funcref boost::process::extend::get_io_context ex::get_io_context]] +[def __require_io_context__ [classref boost::process::v1::extend::require_io_context ex::require_io_context]] +[def __async_handler__ [classref boost::process::v1::extend::async_handler ex::async_handler]] +[def __get_io_context__ [funcref boost::process::v1::extend::get_io_context ex::get_io_context]] [section:extend Extensions] To extend the library, the header [headerref boost/process/extend.hpp extend] is provided. @@ -16,7 +16,7 @@ To extend the library, the header [headerref boost/process/extend.hpp extend] is It only provides the explicit style for custom properties, but no implicit style. What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions. -If a class inherits [classref boost::process::extend::handler] it will be regarded as an initializer and thus directly put into the sequence +If a class inherits [classref boost::process::v1::extend::handler] it will be regarded as an initializer and thus directly put into the sequence the executor gets passed. [section:structure Structure] @@ -24,9 +24,9 @@ the executor gets passed. The executor calls different handlers of the initializers during the process launch. The basic structure consists of three functions, as given below: -* [globalref boost::process::extend::on_setup on_setup] -* [globalref boost::process::extend::on_error on_error] -* [globalref boost::process::extend::on_success on_success] +* [globalref boost::process::v1::extend::on_setup on_setup] +* [globalref boost::process::v1::extend::on_error on_error] +* [globalref boost::process::v1::extend::on_success on_success] ''' @@ -34,11 +34,11 @@ The basic structure consists of three functions, as given below: Additionally posix provides three more handlers, listed below: -* [globalref boost::process::extend::on_fork_error on_fork_error] -* [globalref boost::process::extend::on_exec_setup on_exec_setup] -* [globalref boost::process::extend::on_exec_error on_exec_error] +* [globalref boost::process::v1::extend::on_fork_error on_fork_error] +* [globalref boost::process::v1::extend::on_exec_setup on_exec_setup] +* [globalref boost::process::v1::extend::on_exec_error on_exec_error] -For more information see the reference of [classref boost::process::extend::posix_executor posix_executor]. +For more information see the reference of [classref boost::process::v1::extend::posix_executor posix_executor]. [endsect] [section:simple Simple extensions] @@ -55,8 +55,8 @@ __child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << Considering that lambdas can also capture values, data can easily be shared between handlers. -To see which members the executor has, refer to [classref boost::process::extend::windows_executor windows_executor] -and [classref boost::process::extend::posix_executor posix_executor]. +To see which members the executor has, refer to [classref boost::process::v1::extend::windows_executor windows_executor] +and [classref boost::process::v1::extend::posix_executor posix_executor]. [note Combined with __on_exit__ this can also handle the process exit.] @@ -67,7 +67,7 @@ and [classref boost::process::extend::posix_executor posix_executor]. [section:handler Handler Types] Since the previous example is in a functional style, it is not very reusable. -To solve that problem, the [classref boost::process::extend::handler handler] has an alias in the `boost::process::extend` namespace, to be inherited. +To solve that problem, the [classref boost::process::v1::extend::handler handler] has an alias in the `boost::process::v1::extend` namespace, to be inherited. So let's implement the hello world example in a class. ``` @@ -86,7 +86,7 @@ __child__ c("foo", hello_world()); [note The implementation is done via overloading, not overriding.] -Every handler not implemented defaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event. +Every handler not implemented defaults to [classref boost::process::v1::extend::handler handler], where an empty handler is defined for each event. [endsect] @@ -108,11 +108,11 @@ struct async_foo : __handler__, __require_io_context__ } }; ``` -[note Inheriting [globalref boost::process::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::system system] provides one.] +[note Inheriting [globalref boost::process::v1::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::v1::system system] provides one.] Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__. -[note [globalref boost::process::extend::async_handler async_handler] implies [globalref boost::process::extend::require_io_context require_io_context] .] +[note [globalref boost::process::v1::extend::async_handler async_handler] implies [globalref boost::process::v1::extend::require_io_context require_io_context] .] ``` struct async_bar : __handler, __async_handler__ @@ -131,7 +131,7 @@ struct async_bar : __handler, __async_handler__ ``` -[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ] +[caution `on_exit_handler` does not default and is always required when [classref boost::process::v1::extend::async_handler async_handler] is inherited. ] [caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ] @@ -156,7 +156,7 @@ auto set_error = [](auto & exec) __child__ c("foo", on_setup=set_error); ``` -Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::process_error process_error]. +Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::v1::process_error process_error]. [endsect] diff --git a/doc/faq.qbk b/doc/v1/faq.qbk similarity index 100% rename from doc/faq.qbk rename to doc/v1/faq.qbk diff --git a/doc/introduction.qbk b/doc/v1/introduction.qbk similarity index 71% rename from doc/introduction.qbk rename to doc/v1/introduction.qbk index 060a78123..e9fe67f2d 100644 --- a/doc/introduction.qbk +++ b/doc/v1/introduction.qbk @@ -10,15 +10,15 @@ Boost.Process is a library to manage system processes. It can be used to: Here's a simple example of how to start a program with Boost.Process: -[def ipstream [classref boost::process::ipstream ipstream]] -[def system [funcref boost::process::system system]] -[def std_out [globalref boost::process::std_out std_out]] -[def child [globalref boost::process::child child]] +[def ipstream [classref boost::process::v1::ipstream ipstream]] +[def system [funcref boost::process::v1::system system]] +[def std_out [globalref boost::process::v1::std_out std_out]] +[def child [globalref boost::process::v1::child child]] [def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]] [def std::string [@http://en.cppreference.com/w/cpp/string/basic_string std::string]] [def std::getline [@http://en.cppreference.com/w/cpp/string/basic_string/getline std::getline]] -[import ../example/intro.cpp] +[import ../../example/intro.cpp] [intro] [endsect] diff --git a/doc/v1/posix_pseudocode.xml b/doc/v1/posix_pseudocode.xml new file mode 100644 index 000000000..699d087e5 --- /dev/null +++ b/doc/v1/posix_pseudocode.xml @@ -0,0 +1,60 @@ + + +for (auto & s : seq) + s.on_setup(*this); + +if (error()) +{ + for (auto & s : seq) + s.on_error(*this, error()); + return child(); +} + +pid = fork() +on_setup(*this); + +if (pid == -1) //fork error +{ + set_error(get_last_error()); + for (auto & s : seq) + s.on_fork_error(*this, error()); + for (auto & s : seq) + s.on_error(*this, error()); + return child() +} +else if (pid == 0) //child process +{ + for (auto & s : seq) + s.on_exec_setup(*this); + execve(exe, cmd_line, env); + auto ec = get_last_error(); + for (auto & s : seq) + s.on_exec_error(*this); + + unspecified();//here the error is sent to the father process internally + + std::exit(EXIT_FAILURE); + return child(); //for C++ compliance +} + +child c(pid, exit_code); + +unspecified();//here, we read the error from the child process + +if (error()) + for (auto & s : seq) + s.on_error(*this, error()); +else + for (auto & s : seq) + s.on_success(*this); + +//now we check again, because an on_success handler might've errored. +if (error()) +{ + for (auto & s : seq) + s.on_error(*this, error()); + return child(); +} +else + return c; + \ No newline at end of file diff --git a/doc/tutorial.qbk b/doc/v1/tutorial.qbk similarity index 78% rename from doc/tutorial.qbk rename to doc/v1/tutorial.qbk index 4b208b466..e7e98a2b0 100644 --- a/doc/tutorial.qbk +++ b/doc/v1/tutorial.qbk @@ -1,49 +1,49 @@ -[def bp::system [funcref boost::process::system bp::system]] -[def bp::async_system [funcref boost::process::async_system bp::async_system]] -[def bp::spawn [funcref boost::process::spawn bp::spawn]] -[def bp::child [classref boost::process::child bp::child]] -[def bp::cmd [classref boost::process::cmd bp::cmd]] -[def bp::group [classref boost::process::group bp::group]] -[def bp::ipstream [classref boost::process::ipstream bp::ipstream]] -[def bp::opstream [classref boost::process::opstream bp::opstream]] -[def bp::pstream [classref boost::process::pstream bp::pstream]] -[def bp::pipe [classref boost::process::pipe bp::pipe]] -[def bp::async_pipe [classref boost::process::async_pipe bp::async_pipe]] -[def bp::search_path [funcref boost::process::search_path bp::search_path]] +[def bp::system [funcref boost::process::v1::system bp::system]] +[def bp::async_system [funcref boost::process::v1::async_system bp::async_system]] +[def bp::spawn [funcref boost::process::v1::spawn bp::spawn]] +[def bp::child [classref boost::process::v1::child bp::child]] +[def bp::cmd [classref boost::process::v1::cmd bp::cmd]] +[def bp::group [classref boost::process::v1::group bp::group]] +[def bp::ipstream [classref boost::process::v1::ipstream bp::ipstream]] +[def bp::opstream [classref boost::process::v1::opstream bp::opstream]] +[def bp::pstream [classref boost::process::v1::pstream bp::pstream]] +[def bp::pipe [classref boost::process::v1::pipe bp::pipe]] +[def bp::async_pipe [classref boost::process::v1::async_pipe bp::async_pipe]] +[def bp::search_path [funcref boost::process::v1::search_path bp::search_path]] [def boost_org [@www.boost.org "www.boost.org"]] [def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]] -[def child_running [memberref boost::process::child::running running]] -[def child_wait [memberref boost::process::child::wait wait]] -[def child_wait_for [memberref boost::process::child::wait_for wait_for]] -[def child_exit_code [memberref boost::process::child::exit_code exit_code]] -[def group_wait_for [memberref boost::process::group::wait_for wait_for]] -[def bp::on_exit [globalref boost::process::on_exit bp::on_exit]] -[def bp::null [globalref boost::process::null bp::null]] -[def child_terminate [memberref boost::process::child::terminate terminate]] -[def group_terminate [memberref boost::process::group::terminate terminate]] -[def group_wait [memberref boost::process::group::wait wait]] -[def bp::std_in [globalref boost::process::std_in bp::std_in]] -[def bp::std_out [globalref boost::process::std_out bp::std_out]] -[def bp::std_err [globalref boost::process::std_err bp::std_err]] +[def child_running [memberref boost::process::v1::child::running running]] +[def child_wait [memberref boost::process::v1::child::wait wait]] +[def child_wait_for [memberref boost::process::v1::child::wait_for wait_for]] +[def child_exit_code [memberref boost::process::v1::child::exit_code exit_code]] +[def group_wait_for [memberref boost::process::v1::group::wait_for wait_for]] +[def bp::on_exit [globalref boost::process::v1::on_exit bp::on_exit]] +[def bp::null [globalref boost::process::v1::null bp::null]] +[def child_terminate [memberref boost::process::v1::child::terminate terminate]] +[def group_terminate [memberref boost::process::v1::group::terminate terminate]] +[def group_wait [memberref boost::process::v1::group::wait wait]] +[def bp::std_in [globalref boost::process::v1::std_in bp::std_in]] +[def bp::std_out [globalref boost::process::v1::std_out bp::std_out]] +[def bp::std_err [globalref boost::process::v1::std_err bp::std_err]] [def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]] [def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]] [def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]] -[def bp::environment [classref boost::process::basic_environment bp::environment]] -[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]] +[def bp::environment [classref boost::process::v1::basic_environment bp::environment]] +[def bp::native_environment [classref boost::process::v1::basic_native_environment bp::native_environment]] [def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]] [def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]] [def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]] -[def __wait_for__ [memberref boost::process::child::wait_for wait_for]] -[def __wait_until__ [memberref boost::process::child::wait_until wait_until]] -[def __detach__ [memberref boost::process::child::detach detach]] +[def __wait_for__ [memberref boost::process::v1::child::wait_for wait_for]] +[def __wait_until__ [memberref boost::process::v1::child::wait_until wait_until]] +[def __detach__ [memberref boost::process::v1::child::detach detach]] [def __reference__ [link process.reference reference]] [def __concepts__ [link boost_process.concepts concepts]] [def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]] [def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]] -[def bp::env [globalref boost::process::env bp::env]] +[def bp::env [globalref boost::process::v1::env bp::env]] [section:tutorial Tutorial] @@ -82,10 +82,10 @@ int result = bp::system("/usr/bin/g++", "main.cpp"); ``` With that syntax we still have "g++" hard-coded, so let's assume we get the string -from an external source as `boost::process::filesystem::path`, we can do this too. +from an external source as `boost::process::v1::filesystem::path`, we can do this too. ``` -boost::process::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else. +boost::process::v1::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else. int result = bp::system(p, "main.cpp"); ``` @@ -93,28 +93,28 @@ Now we might want to find the `g++` executable in the `PATH`-variable, as the `c `Boost.process` provides a function to this end: bp::search_path. ``` -boost::process::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else. +boost::process::v1::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else. int result = bp::system(p, "main.cpp"); ``` -[note [funcref boost::process::search_path search_path] will search for any executable with that name. +[note [funcref boost::process::v1::search_path search_path] will search for any executable with that name. This also includes to add a file suffix on windows, such as `.exe` or `.bat`.] [endsect] [section:launch_mode Launch functions] -Given that our example used the [funcref boost::process::system system] function, +Given that our example used the [funcref boost::process::v1::system system] function, our program will wait until the child process is completed. This may be unwanted, especially since compiling can take a while. In order to avoid that, boost.process provides several ways to launch a process. -Besides the already mentioned [funcref boost::process::system system] function and its -asynchronous version [funcref boost::process::async_system async_system], -we can also use the [funcref boost::process::spawn spawn] function or the -[classref boost::process::child child] class. +Besides the already mentioned [funcref boost::process::v1::system system] function and its +asynchronous version [funcref boost::process::v1::async_system async_system], +we can also use the [funcref boost::process::v1::spawn spawn] function or the +[classref boost::process::v1::child child] class. -The [funcref boost::process::spawn spawn] function launches a process and +The [funcref boost::process::v1::spawn spawn] function launches a process and immediately detaches it, so no handle will be returned and the process will be ignored. This is not what we need for compiling, but maybe we want to entertain the user, while compiling: @@ -124,7 +124,7 @@ bp::spawn(bp::search_path("chrome"), boost_org); ``` Now for the more sensible approach for compiling: a non-blocking execution. -To implement that, we directly call the constructor of [classref boost::process::child child]. +To implement that, we directly call the constructor of [classref boost::process::v1::child child]. ``` bp::child c(bp::search_path("g++"), "main.cpp"); @@ -189,9 +189,9 @@ Now, let's take a more visual example for reading data. which reads the outline, i.e. a list of all entry points, of a binary. Every entry point will be put into a single line, and we will use a pipe to read it. At the end an empty line is appended, which we use as the indication to stop reading. -Boost.process provides the pipestream ([classref boost::process::ipstream ipstream], -[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to -wrap around the [classref boost::process::pipe pipe] and provide an implementation of the +Boost.process provides the pipestream ([classref boost::process::v1::ipstream ipstream], +[classref boost::process::v1::opstream opstream], [classref boost::process::v1::pstream pstream]) to +wrap around the [classref boost::process::v1::pipe pipe] and provide an implementation of the [@http://en.cppreference.com/w/cpp/io/basic_istream std::istream], [@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and [@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface. @@ -217,7 +217,7 @@ std::vector read_outline(std::string & file) What this does is redirect the `stdout` of the process into a pipe and we read this synchronously. -[note You can do the same thing with [globalref boost::process::std_err std_err].] +[note You can do the same thing with [globalref boost::process::v1::std_err std_err].] Now we get the name from `nm` and we might want to demangle it, so we use input and output. `nm` has a demangle option, but for the sake of the example, we'll use @@ -267,8 +267,8 @@ This forwards the data from `nm` to `c++filt` without your process needing to do Boost.process allows the usage of boost.asio to implement asynchronous I/O. If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend), -you can use [classref boost::process::async_pipe async_pipe] which is implemented -as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above. +you can use [classref boost::process::v1::async_pipe async_pipe] which is implemented +as an I/O-Object and can be used like [classref boost::process::v1::pipe pipe] as shown above. Now we get back to our compiling example. For `nm` we might analyze the output line by line, but the compiler output will just be put into one large buffer. @@ -304,7 +304,7 @@ int result = c.exit_code(); ``` [note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of -[memberref boost::process::child::wait wait] is needed.] +[memberref boost::process::v1::child::wait wait] is needed.] To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations (you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system. @@ -364,7 +364,7 @@ c.child_wait(); //to avoid a zombie process & get the exit code ``` Now given the example, we still call child_wait to avoid a zombie process. -An easier solution for that might be to use [funcref boost::process::spawn spawn]. +An easier solution for that might be to use [funcref boost::process::v1::spawn spawn]. To put two processes into one group, the following code suffices. Spawn already @@ -412,7 +412,7 @@ bp::system("stuff", env_); ``` A more convenient way to modify the environment for the child is the -[globalref boost::process::env env] property, which can be used in the example as following: +[globalref boost::process::v1::env env] property, which can be used in the example as following: ``` bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"}); diff --git a/doc/v1/windows_pseudocode.xml b/doc/v1/windows_pseudocode.xml new file mode 100644 index 000000000..8cca87bd2 --- /dev/null +++ b/doc/v1/windows_pseudocode.xml @@ -0,0 +1,42 @@ + + +for (auto & s : seq) + s.on_setup(*this); + +if (error()) +{ + for (auto & s : seq) + s.on_error(*this, error()); + return child(); +} +int err_code = CreateProcess( + exe, + cmd_line, + proc_attrs, + thread_attrs, + creation_flags, + env, + work_dir, + startup_info, + proc_info); + +child c(proc_info, exit_code); + +if (error()) + for (auto & s : seq) + s.on_error(*this, error()); +else + for (auto & s : seq) + s.on_success(*this); + +//now we check again, because an on_success handler might've errored. +if (error()) +{ + for (auto & s : seq) + s.on_error(*this, error()); + return child(); +} +else + return c; + + \ No newline at end of file diff --git a/doc/v2/stdio.qbk b/doc/v2/stdio.qbk index b21f6f718..915cdfd2c 100644 --- a/doc/v2/stdio.qbk +++ b/doc/v2/stdio.qbk @@ -12,7 +12,7 @@ automatically connected and the other side will get assigned to the child proces ``` asio::io_context ctx; - asio::readable_pipe rp; + asio::readable_pipe rp{ctx}; process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }}); std::string output; @@ -86,4 +86,4 @@ It starts a process and connects pipes for stdin and stdout, so that the popen o [endsect] -[endsect] \ No newline at end of file +[endsect] diff --git a/doc/windows_pseudocode.xml b/doc/windows_pseudocode.xml deleted file mode 100644 index fdcb780c8..000000000 --- a/doc/windows_pseudocode.xml +++ /dev/null @@ -1,42 +0,0 @@ - - -for (auto & s : seq) - s.on_setup(*this); - -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -int err_code = CreateProcess( - exe, - cmd_line, - proc_attrs, - thread_attrs, - creation_flags, - env, - work_dir, - startup_info, - proc_info); - -child c(proc_info, exit_code); - -if (error()) - for (auto & s : seq) - s.on_error(*this, error()); -else - for (auto & s : seq) - s.on_success(*this); - -//now we check again, because an on_success handler might've errored. -if (error()) -{ - for (auto & s : seq) - s.on_error(*this, error()); - return child(); -} -else - return c; - - \ No newline at end of file diff --git a/example/io.cpp b/example/io.cpp index 97ace20ad..7b5142da8 100644 --- a/example/io.cpp +++ b/example/io.cpp @@ -22,7 +22,7 @@ int main() bp::std_in < bp::null //null in ); - boost::process::filesystem::path p = "input.txt"; + boost::process::v1::filesystem::path p = "input.txt"; bp::system( "test.exe", diff --git a/example/posix.cpp b/example/posix.cpp index 4e937222a..e822af764 100644 --- a/example/posix.cpp +++ b/example/posix.cpp @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include -#include +#include +#include #include #include #include diff --git a/example/start_dir.cpp b/example/start_dir.cpp index fbeb19d52..fa7ae7649 100644 --- a/example/start_dir.cpp +++ b/example/start_dir.cpp @@ -8,7 +8,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include namespace bp = boost::process; @@ -19,9 +19,9 @@ int main() bp::start_dir="../foo" ); - boost::process::filesystem::path exe = "test.exe"; + boost::process::v1::filesystem::path exe = "test.exe"; bp::system( - boost::process::filesystem::absolute(exe), + boost::process::v1::filesystem::absolute(exe), bp::start_dir="../foo" ); } diff --git a/example/windows.cpp b/example/windows.cpp index aba35853f..93b4f62c9 100644 --- a/example/windows.cpp +++ b/example/windows.cpp @@ -8,8 +8,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include -#include +#include +#include #include #include diff --git a/include/boost/process.hpp b/include/boost/process.hpp index 1bf59516f..5702e5b52 100644 --- a/include/boost/process.hpp +++ b/include/boost/process.hpp @@ -19,24 +19,16 @@ * boost.process header files. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#if !defined(BOOST_PROCESS_VERSION) +#define BOOST_PROCESS_VERSION 1 +#endif + +#if BOOST_PROCESS_VERSION == 1 +#include +#elif BOOST_PROCESS_VERSION == 2 +#include +#else +#error "Unknown boost process version" +#endif #endif diff --git a/include/boost/process/args.hpp b/include/boost/process/args.hpp index 8b6b3354f..09584fbb0 100644 --- a/include/boost/process/args.hpp +++ b/include/boost/process/args.hpp @@ -1,279 +1,9 @@ -// 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 +// Copyright (c) 2024 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 args\endxmlonly property. It also provides the - * alternative name \xmlonly argv\endxmlonly . - * - * -\xmlonly - -namespace boost { - namespace process { - unspecified args; - unspecified argv; - } -} - -\endxmlonly - */ - - -#include -#include - -namespace boost { namespace process { namespace detail { - -struct args_ -{ - template - using remove_reference_t = typename std::remove_reference::type; - template - using value_type = typename remove_reference_t::value_type; - - template - using vvalue_type = value_type>; - - template - arg_setter_, true> operator()(Range &&range) const - { - return arg_setter_, true>(std::forward(range)); - } - template - arg_setter_, true> operator+=(Range &&range) const - { - return arg_setter_, true>(std::forward(range)); - } - template - arg_setter_, false> operator= (Range &&range) const - { - return arg_setter_, false>(std::forward(range)); - } - template - arg_setter_ operator()(std::basic_string && str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator+=(std::basic_string && str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator= (std::basic_string && str) const - { - return arg_setter_(str); - } - template - arg_setter_ operator()(const std::basic_string & str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator+=(const std::basic_string & str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator= (const std::basic_string & str) const - { - return arg_setter_(str); - } - template - arg_setter_ operator()(std::basic_string & str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator+=(std::basic_string & str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator= (std::basic_string & str) const - { - return arg_setter_(str); - } - template - arg_setter_ operator()(const Char* str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator+=(const Char* str) const - { - return arg_setter_ (str); - } - template - arg_setter_ operator= (const Char* str) const - { - return arg_setter_(str); - } -// template -// arg_setter_ operator()(const Char (&str) [Size]) const -// { -// return arg_setter_ (str); -// } -// template -// arg_setter_ operator+=(const Char (&str) [Size]) const -// { -// return arg_setter_ (str); -// } -// template -// arg_setter_ operator= (const Char (&str) [Size]) const -// { -// return arg_setter_(str); -// } - - arg_setter_ operator()(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator+=(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator= (std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator()(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator+=(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator= (std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - - arg_setter_ operator()(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator+=(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator= (std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator()(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator+=(std::initializer_list &&range) const - { - return arg_setter_(range.begin(), range.end()); - } - arg_setter_ operator= (std::initializer_list &&range) const - { - return arg_setter_(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` - - `const char_type * ` - - `std::initializer_list` - - `std::vector>` - -Additionally any range of `std::basic_string` 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` - - `const char_type * ` - - `std::initializer_list` - - `std::vector>` - -Additionally any range of `std::basic_string` 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 args \endxmlonly . -constexpr boost::process::detail::args_ argv{}; - - -}} - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/async.hpp b/include/boost/process/async.hpp index e0d002225..65137600a 100644 --- a/include/boost/process/async.hpp +++ b/include/boost/process/async.hpp @@ -1,132 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 asynchronous 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_context, -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 - -namespace boost { - namespace process { - unspecified buffer; - unspecified on_exit; - } -} - - -\endxmlonly - */ - -#ifndef BOOST_PROCESS_ASYNC_HPP_ -#define BOOST_PROCESS_ASYNC_HPP_ - -#include -#include - -#include -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#include -#include -#include - -#elif defined(BOOST_WINDOWS_API) -#include -#include -#include -#include -#endif - -namespace boost { namespace process { namespace detail { - -struct async_tag; - -template -struct is_io_context : std::false_type {}; -template<> -struct is_io_context : std::true_type {}; - -template -inline asio::io_context& get_io_context(const Tuple & tup) -{ - auto& ref = *boost::fusion::find_if>(tup); - return ref.get(); -} - -struct async_builder -{ - boost::asio::io_context * ios; - - void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;}; - - typedef api::io_context_ref result_type; - api::io_context_ref get_initializer() {return api::io_context_ref (*ios);}; -}; - - -template<> -struct initializer_builder -{ - typedef async_builder type; -}; - -} - -using ::boost::asio::buffer; - - -#if defined(BOOST_PROCESS_DOXYGEN) -/** When an io_context 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`. - -\par Example - -\code{.cpp} -io_context ios; - -child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){}); - -std::future exit_code; -chlid c2("ls", ios, on_exit=exit_code); - -\endcode - -\note The handler is not invoked when the launch fails. -\warning When used \ref ignore_error it might get invoked on error. -\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the -same restrictions as that class (do not register a handler for `SIGCHLD` except by using -`boost::asio::signal_set`). - */ -constexpr static ::boost::process::detail::on_exit_ on_exit{}; -#endif - -}} - - - -#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/async_pipe.hpp b/include/boost/process/async_pipe.hpp index 0982b9041..1e91d28fb 100644 --- a/include/boost/process/async_pipe.hpp +++ b/include/boost/process/async_pipe.hpp @@ -1,217 +1,9 @@ -// 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) 2024 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_ASYNC_PIPE_HPP -#define BOOST_PROCESS_ASYNC_PIPE_HPP - -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -namespace boost { namespace process { - - -#if defined(BOOST_PROCESS_DOXYGEN) - - -/** Class implementing an 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; - - typedef typename handle_type::executor_type executor_type; - - /** Construct a new async_pipe, does automatically open the pipe. - * Initializes source and sink with the same io_context. - * @note Windows creates a named pipe here, where the name is automatically generated. - */ - inline async_pipe(boost::asio::io_context & 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_context & ios_source, - boost::asio::io_context & ios_sink); - - /** Construct a new async_pipe, does automatically open. - * Initializes source and sink with the same io_context. - * - * @note Windows restricts possible names. - */ - inline async_pipe(boost::asio::io_context & ios, const std::string & name); - - - /** Construct a new async_pipe, does automatically open. - * - * @note Windows restricts possible names. - */ - inline async_pipe(boost::asio::io_context & ios_source, - boost::asio::io_context & 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> - explicit async_pipe(boost::asio::io_context & ios, const basic_pipe & p); - - /** Construct the async-pipe from a pipe, with two different io_context objects. - * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. - * - */ - template> - explicit async_pipe(boost::asio::io_context & ios_source, - boost::asio::io_context & ios_sink, - const basic_pipe & 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> - inline async_pipe& operator=(const basic_pipe& 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> - inline explicit operator basic_pipe() 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 - std::size_t read_some(const MutableBufferSequence & buffers); - - /** Write some data to the handle. - - * See the boost.asio documentation for more details. - */ - template - std::size_t write_some(const MutableBufferSequence & buffers); - - /** Get the native handle of the source. */ - native_handle native_source() const {return const_cast(_source).native();} - /** Get the native handle of the sink. */ - native_handle native_sink () const {return const_cast(_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 - 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 - 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_context. Qualified as rvalue. \attention Will always move. - handle_type source(::boost::asio::io_context& ios) &&; - /// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move - handle_type sink (::boost::asio::io_context& ios) &&; - - /// Copy the source out of this class and change the io_context. \attention Will always copy. - handle_type source(::boost::asio::io_context& ios) const &; - /// Copy the sink out of this class and change the io_context. \attention Will always copy - handle_type sink (::boost::asio::io_context& ios) const &; - - - -}; - -#else -using ::boost::process::detail::api::async_pipe; -#endif - - -}} - - - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/async_system.hpp b/include/boost/process/async_system.hpp index c11acafe0..86b967365 100644 --- a/include/boost/process/async_system.hpp +++ b/include/boost/process/async_system.hpp @@ -1,151 +1,9 @@ -// 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 +// Copyright (c) 2024 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 asynchronous version of the system function. - */ - -#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP -#define BOOST_PROCESS_ASYNC_SYSTEM_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#endif - -namespace boost { -namespace process { -namespace detail -{ - -template -struct async_system_handler : ::boost::process::detail::api::async_handler -{ - boost::asio::io_context & ios; - Handler handler; - -#if defined(BOOST_POSIX_API) - bool errored = false; -#endif - - template - async_system_handler( - boost::asio::io_context & ios, - ExitHandler_ && exit_handler) : ios(ios), handler(std::forward(exit_handler)) - { - } - - - template - void on_error(Exec&, const std::error_code & ec) - { -#if defined(BOOST_POSIX_API) - errored = true; -#endif - auto h = std::make_shared(std::move(handler)); - boost::asio::post( - ios.get_executor(), - [h, ec]() mutable - { - (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1); - }); - } - - template - std::function on_exit_handler(Executor&) - { -#if defined(BOOST_POSIX_API) - if (errored) - return [](int , const std::error_code &){}; -#endif - auto h = std::make_shared(std::move(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 -struct is_error_handler> : 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_context](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 -inline boost::process::detail::dummy - async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args); -#endif - -namespace detail -{ -struct async_system_init_op -{ - - template - void operator()(Handler && handler, asio::io_context & ios, Args && ... args) - { - detail::async_system_handler::type> async_h{ios, std::forward(handler)}; - child(ios, std::forward(args)..., async_h ).detach(); - } -}; - - -} - - -template -inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) - async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args) -{ - - typedef typename ::boost::process::detail::has_error_handler>::type - has_err_handling; - - static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); - - return boost::asio::async_initiate( - detail::async_system_init_op{}, exit_handler, ios, std::forward(args)... - ); -} - - - -}} -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/child.hpp b/include/boost/process/child.hpp index 8e6dcdd08..ad02db72b 100644 --- a/include/boost/process/child.hpp +++ b/include/boost/process/child.hpp @@ -1,154 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#endif - -namespace boost { - -///The main namespace of boost.process. -namespace process { - -template -child::child(Args&&...args) - : child(::boost::process::detail::execute_impl(std::forward(args)...)) {} - - -///Typedef for the type of an pid_t -typedef ::boost::process::detail::api::pid_t pid_t; - -#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 - 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; - - /** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited - * for or if it was terminated. */ - int native_exit_code() 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& rel_time); - /** \overload bool wait_for(const std::chrono::duration& rel_time) */ - bool wait_for (const std::chrono::duration& 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& timeout_time ); - /** \overload bool wait_until(const std::chrono::time_point& timeout_time )*/ - bool wait_until(const std::chrono::time_point& 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 +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/cmd.hpp b/include/boost/process/cmd.hpp index ddba0068a..ccf44fd21 100644 --- a/include/boost/process/cmd.hpp +++ b/include/boost/process/cmd.hpp @@ -1,122 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -/** \file boost/process/cmd.hpp - * - * This header provides the \xmlonly cmd\endxmlonly property. - * -\xmlonly - -namespace boost { - namespace process { - unspecified cmd; - } -} - -\endxmlonly -*/ - -namespace boost { namespace process { namespace detail { - - -struct cmd_ -{ - constexpr cmd_() = default; - - template - inline api::cmd_setter_ operator()(const Char *s) const - { - return api::cmd_setter_(s); - } - template - inline api::cmd_setter_ operator= (const Char *s) const - { - return api::cmd_setter_(s); - } - - template - inline api::cmd_setter_ operator()(const std::basic_string &s) const - { - return api::cmd_setter_(s); - } - template - inline api::cmd_setter_ operator= (const std::basic_string &s) const - { - return api::cmd_setter_(s); - } -}; - -template<> struct is_wchar_t> : std::true_type {}; - - - -template<> -struct char_converter> -{ - static api::cmd_setter_ conv(const api::cmd_setter_ & in) - { - return { ::boost::process::detail::convert(in.str()) }; - } -}; - -template<> -struct char_converter> -{ - static api::cmd_setter_ conv(const api::cmd_setter_ & 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 +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/detail/traits.hpp b/include/boost/process/detail/traits.hpp deleted file mode 100644 index 83789d9d0..000000000 --- a/include/boost/process/detail/traits.hpp +++ /dev/null @@ -1,17 +0,0 @@ -// 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 -#include -#include -#include -#include -#include - -#endif /* BOOST_PROCESS_TRAITS_HPP_ */ diff --git a/include/boost/process/env.hpp b/include/boost/process/env.hpp index 1457a0dcc..aa8145aeb 100644 --- a/include/boost/process/env.hpp +++ b/include/boost/process/env.hpp @@ -1,503 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#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 - -namespace boost { - namespace process { - unspecified env; - } -} - - * \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 -std::size_t make_env_string_size(const std::basic_string & ch) -{ - return ch.size() + 1; -} - -template -std::size_t make_env_string_size(const Char * ch) -{ - std::size_t sz = 0; - while (ch[sz] != null_char()) - sz++; - - sz++; - return sz; -} - -template -inline std::basic_string make_env_string(const Container & value) -{ - std::size_t sz = 0; - for (auto & v : value) - sz += make_env_string_size(v); - - std::basic_string s; - s.reserve(sz); //+1 for ;, end doesn't have one. - - for (auto & val : value) - (s += val) += api::env_seperator(); - - s.resize(s.size() -1); //remove last ';' - return s; -} - - -template -struct env_set -{ - using string_type = std::basic_string; - string_type key; - string_type value; -}; - -template -struct env_append -{ - using string_type = std::basic_string; - string_type key; - string_type value; -}; - - - -template -struct env_reset -{ - using string_type = std::basic_string; - string_type key; -}; - - -template<> struct is_wchar_t> : std::true_type {}; -template<> struct is_wchar_t> : std::true_type {}; -template<> struct is_wchar_t> : std::true_type {}; -template<> struct is_wchar_t> : std::true_type {}; - - -template<> -struct char_converter> -{ - static env_set conv(const env_set & in) - { - return {::boost::process::detail::convert(in.key), - ::boost::process::detail::convert(in.value)}; - } -}; - -template<> -struct char_converter> -{ - static env_set conv(const env_set & in) - { - return {::boost::process::detail::convert(in.key), - ::boost::process::detail::convert(in.value)}; - } -}; - -template<> -struct char_converter> -{ - static env_append conv(const env_append & in) - { - return {::boost::process::detail::convert(in.key), - ::boost::process::detail::convert(in.value)}; - } -}; - -template<> -struct char_converter> -{ - static env_append conv(const env_append & in) - { - return {::boost::process::detail::convert(in.key), - ::boost::process::detail::convert(in.value)}; - } -}; - -template<> -struct char_converter> -{ - static env_reset conv(const env_reset & in) - { - return {::boost::process::detail::convert(in.key)}; - } -}; - -template<> -struct char_converter> -{ - static env_reset conv(const env_reset & in) - { - return {::boost::process::detail::convert(in.key)}; - } -}; - - -template -struct env_init -{ - basic_environment env; -}; - -template<> -struct char_converter> -{ - static env_init conv(const env_init & in) - { - return {basic_environment(in.env)}; - } -}; - -template<> -struct char_converter> -{ - static env_init conv(const env_init & in) - { - return {basic_environment(in.env)}; - } -}; - -template<> -struct char_converter> -{ - static basic_environment conv(const basic_environment & in) - { - return { basic_environment(in) }; - } -}; - -template<> -struct char_converter> -{ - static basic_environment conv(const basic_environment & in) - { - return { basic_environment(in) }; - } -}; - -template -struct env_proxy -{ - using string_type = std::basic_string; - string_type key; - - - env_set operator=(const string_type & value) - { - return {std::move(key), value}; - } - env_set operator=(const std::vector & value) - { - return {std::move(key), make_env_string(value)}; - } - env_set operator=(const std::initializer_list & value) - { - return {std::move(key), make_env_string(value)}; - } - - env_append operator+=(const string_type & value) - { - return {std::move(key), value}; - } - env_append operator+=(const std::vector & value) - { - return {std::move(key), make_env_string(value)}; - } - env_append operator+=(const std::initializer_list & value) - { - return {std::move(key), make_env_string(value)}; - } - env_reset operator=(boost::none_t) - { - return {std::move(key)}; - } -}; - -struct env_ -{ - constexpr env_() {}; - - template - env_set operator()(const std::basic_string & key, - const std::basic_string & value) const - { - return {key, value}; - } - template - env_set operator()(const std::basic_string & key, - const std::vector> & value) const - { - return {key, make_env_string(value)}; - } - template - env_set operator()(const std::basic_string & key, - const std::initializer_list & value) const - { - return {key, make_env_string(value)}; - } - template - env_reset operator()(const std::basic_string & key, boost::none_t) - { - return {key}; - } - template - env_proxy operator[](const std::basic_string & key) const - { - return {key}; - } - template - env_proxy operator[](const Char* key) const - { - return {key}; - } - template - env_init operator()(const basic_environment & env) const - { - return {env}; - } - template - env_init operator= (const basic_environment & env) const - { - return {env}; - } -}; - -template -struct env_builder -{ - basic_environment env; - env_builder() : env{basic_native_environment()} {} - - void operator()(const basic_environment & e) - { - env = e; - } - - void operator()(env_init & ei) - { - env = std::move(ei.env); - } - void operator()(env_set & es) - { - env[es.key] = es.value; - } - void operator()(env_reset & es) - { - env.erase(es.key); - } - template - void operator()(env_append & es) - { - env[es.key] += es.value; - } - - typedef api::env_init result_type; - api::env_init get_initializer() - { - return api::env_init(std::move(env)); - } -}; - -template<> -struct initializer_builder> -{ - typedef env_builder type; -}; - -template<> -struct initializer_builder> -{ - typedef env_builder type; -}; - -} - -/** - -The `env` property provides a functional way to modify the environment used by -the child process. If none is passed the environment is inherited from the father -process. Appending means that the environment will be interpreted as a ';' or ':' -separated list as used in `PATH`. - -On both `posix` and `windows` the environment variables can be lists of strings, -separated by ';'. This is typically used for the `PATH` variable. - -By default the environment will be inherited from the launching process, -which is also true if environment are modified with this initializer. - -\section env_details Details - -\subsection env_operations Operations - -\subsubsection env_set_var Setting variables - -To set a variable `id` the value `value` the following syntax can be used. - -\code{.cpp} -env[id] = value; -env(id, value); -\endcode - -`std::initializer_list` is among the allowed types, so the following syntax is also possible. - -\code{.cpp} -env[id] = {value1, value2}; -env(id, {value1, value2}); -\endcode - -\note Creates the variable if it does not exist. - -The following lists contain possible value types, with `char_type` being either `char` or `wchar_t` -for both `id` and `value`. - -\paragraph id id - - - `std::basic_string` - - `const char_type *` - -\paragraph env_set_var_value value - - - `std::basic_string` - - `const char_type * ` - - `std::initializer_list` - - `std::vector>` - - -\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` - - `const char_type *` - -\paragraph env_append_var_value value - - - `std::basic_string` - - `const char_type *` - - `std::initializer_list` - - `std::vector>` - - -\subsubsection env_reset Reset variables - -Resetting single 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` - - `const char_type *` - -\subsubsection env_init Initialize the environment - -The whole environment can be initialized from an object of type -\xmlonly boost::process::environment \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` - - `const char_type *` - -\paragraph env_init_var_value value - - - `boost::process::basic_environment` - -\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 boost::process::environment \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_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/environment.hpp b/include/boost/process/environment.hpp index 3b94f2403..9c9727fb5 100644 --- a/include/boost/process/environment.hpp +++ b/include/boost/process/environment.hpp @@ -1,712 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -namespace boost { namespace process { - -namespace detail { - -template -struct const_entry -{ - using value_type = Char ; - using pointer = const value_type * ; - using string_type = std::basic_string ; - using range = boost::iterator_range ; - using environment_t = Environment ; - - std::vector to_vector() const - { - if (_data == nullptr) - return std::vector(); - std::vector data; - auto str = string_type(_data); - struct splitter - { - bool operator()(wchar_t w) const {return w == api::env_seperator();} - bool operator()(char c) const {return c == api::env_seperator ();} - } s; - boost::split(data, _data, s); - return 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 -struct entry : const_entry -{ - using father = const_entry; - 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 &value) - { - string_type data; - for (auto &v : value) - { - if (&v != &value.front()) - data += api::env_seperator(); - data += v; - } - this->_env->set(this->_name, data); - this->reload(); - - } - void assign(const std::initializer_list &value) - { - string_type data; - for (auto &v : value) - { - if (&v != &*value.begin()) - data += api::env_seperator(); - 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); - } - - - 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 & value) - { - assign(value); - return *this; - } - entry &operator=(const std::initializer_list & value) - { - assign(value); - return *this; - } - entry &operator+=(const string_type & value) - { - append(value); - return *this; - } - -}; - - - -template -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 operator()(const Char* data) const - { - auto p = data; - while ((*p != equal_sign()) && (*p != null_char())) - p++; - auto name = std::basic_string(data, p); - p++; //go behind equal sign - - return entry(std::move(name), p, *env); - } -}; - -template -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 operator()(const Char* data) const - { - auto p = data; - while ((*p != equal_sign()) && (*p != null_char())) - p++; - auto name = std::basic_string(data, p); - p++; //go behind equal sign - - return const_entry(std::move(name), p, *env); - } -}; - -} - -#if !defined (BOOST_PROCESS_DOXYGEN) - -template class Implementation = detail::api::basic_environment_impl> -class basic_environment_impl : public Implementation -{ - Char** _get_end() const - { - auto p = this->_env_impl; - while (*p != nullptr) - p++; - - return p; - } -public: - using string_type = std::basic_string; - using implementation_type = Implementation; - using base_type = basic_environment_impl; - using entry_maker = detail::make_entry; - using entry_type = detail::entry ; - using const_entry_type = detail::const_entry ; - using const_entry_maker = detail::make_const_entry; - - 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; - 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(); - while (*p != nullptr) - { - const std::size_t len = std::char_traits::length(*p); - if ((std::distance(st1.begin(), st1.end()) < len) - && 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(); - while (*p != nullptr) - { - const std::size_t len = std::char_traits::length(*p); - if ((std::distance(st1.begin(), st1.end()) < len) - && 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(); - while (*p != nullptr) - { - const std::size_t len = std::char_traits::length(*p); - if ((std::distance(st1.begin(), st1.end()) < - static_cast(len)) - && 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 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(find(id), true); - } - else - return std::pair(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 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 -class basic_environment -{ - -public: - typedef std::basic_string string_type; - typedef boost::transform_iterator< entry_maker, Char**> iterator ; - typedef boost::transform_iterator const_iterator ; - typedef std::size_t size_type ; - - iterator begin() ; /// 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 - struct const_entry_type - { - typedef Char value_type; - typedef const value_type * pointer; - typedef std::basic_string string_type; - typedef boost::iterator_range range; - typedef Environment environment_t; - - ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. - std::vector 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 - struct entry_type - { - - typedef Char value_type; - typedef const value_type * pointer; - typedef std::basic_string string_type; - typedef boost::iterator_range range; - typedef Environment environment_t; - - ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. - std::vector 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 separated by ';' or ':'. - void assign(const std::vector &value); - ///Append a string to the end of the entry, it will separated 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 separated by ';' or ':'. - entry &operator=(const std::vector & value); - ///Append a string to the end of the entry, it will separated 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 -class basic_native_environment -{ - -public: - typedef std::basic_string string_type; - typedef boost::transform_iterator< entry_maker, Char**> iterator ; - typedef boost::transform_iterator const_iterator ; - typedef std::size_t size_type ; - - iterator begin() ; /// 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 - struct const_entry_type - { - typedef Char value_type; - typedef const value_type * pointer; - typedef std::basic_string string_type; - typedef boost::iterator_range range; - typedef Environment environment_t; - - ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. - std::vector 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 - struct entry_type - { - - typedef Char value_type; - typedef const value_type * pointer; - typedef std::basic_string string_type; - typedef boost::iterator_range range; - typedef Environment environment_t; - - ///Split the entry by ";" or ":" and return it as a vector. Used by PATH. - std::vector 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 separated by ';' or ':'. - void assign(const std::vector &value); - ///Append a string to the end of the entry, it will separated 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 separated by ';' or ':'. - entry &operator=(const std::vector & value); - ///Append a string to the end of the entry, it will separated by ';' or ':'. - entry &operator+=(const string_type & value); - }; - -}; - -#endif - -///Definition of the environment for the current process. -template -class basic_native_environment : public basic_environment_impl -{ -public: - using base_type = basic_environment_impl; - using base_type::base_type; - using base_type::operator=; -}; - -///Type definition to hold a seperate environment. -template -class basic_environment : public basic_environment_impl -{ -public: - using base_type = basic_environment_impl; - using base_type::base_type; - using base_type::operator=; -}; - - -#if !defined(BOOST_NO_ANSI_APIS) -///Definition of the environment for the current process. -typedef basic_native_environment native_environment; -#endif -///Definition of the environment for the current process. -typedef basic_native_environment wnative_environment; - -#if !defined(BOOST_NO_ANSI_APIS) -///Type definition to hold a seperate environment. -typedef basic_environment environment; -#endif -///Type definition to hold a seperate environment. -typedef basic_environment 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; - -#if !defined(BOOST_NO_ANSI_APIS) -///Definition of the environment for this process. -using ::boost::process::native_environment; -#endif -///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();} -#if !defined(BOOST_NO_ANSI_APIS) -///Get the enviroment of the current process. -inline native_environment environment() { return ::boost::process:: native_environment(); } -#endif -///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 path() -{ -#if defined(BOOST_WINDOWS_API) - const ::boost::process::wnative_environment ne{}; - typedef typename ::boost::process::wnative_environment::const_entry_type value_type; - static constexpr auto id = L"PATH"; -#else - const ::boost::process::native_environment ne{}; - typedef typename ::boost::process::native_environment::const_entry_type value_type; - static constexpr 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 val; - val.resize(vec.size()); - - std::copy(vec.begin(), vec.end(), val.begin()); - - return val; -} -} -} -#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/error.hpp b/include/boost/process/error.hpp index 69c9a8955..347947457 100644 --- a/include/boost/process/error.hpp +++ b/include/boost/process/error.hpp @@ -1,211 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include - - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** \file boost/process/error.hpp - * - * Header which provides the error properties. It allows to explicitly set the error handling, the properties are: - * -\xmlonly - -namespace boost { - namespace process { - unspecified ignore_error; - unspecified throw_on_error; - unspecified error; - unspecified error_ref; - unspecified error_code; - } -} - -\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_() = default; - - template - 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_() = default; -}; - -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 - void on_error(Executor&, const std::error_code & ec) const noexcept - { - ec_ = ec; - } - -private: - std::error_code &ec_; -}; - -struct error_ -{ - constexpr error_() = default; - 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 -struct is_error_handler : std::false_type {}; - -template<> struct is_error_handler : std::true_type {}; -template<> struct is_error_handler : std::true_type {}; -template<> struct is_error_handler : std::true_type {}; - - - -template -struct has_error_handler_impl -{ - typedef typename boost::fusion::result_of::deref::type ref_type; - typedef typename std::remove_reference::type res_type_; - typedef typename std::remove_cv::type res_type; - typedef typename is_error_handler::type cond; - - typedef typename boost::fusion::result_of::next::type next_itr; - typedef typename has_error_handler_impl::type next; - - typedef typename boost::mpl::or_::type type; -}; - -template -struct has_error_handler_impl -{ - typedef boost::mpl::false_ type; -}; - - -template -struct has_error_handler -{ - typedef typename boost::fusion::result_of::as_vector::type vector_type; - - typedef typename has_error_handler_impl< - typename boost::fusion::result_of::begin::type, - typename boost::fusion::result_of::end< vector_type>::type - >::type type; -}; - -template -struct has_ignore_error -{ - typedef typename boost::fusion::result_of::as_set::type set_type; - typedef typename boost::fusion::result_of::has_key::type type1; - typedef typename boost::fusion::result_of::has_key::type type2; - typedef typename boost::fusion::result_of::has_key::type type3; - typedef typename boost::mpl::or_::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 -{ - typedef error_tag type; -}; - - -template<> -struct initializer_builder -{ - 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 error \endxmlonly . -constexpr boost::process::detail::error_ error_ref; -///Alias for \xmlonly error \endxmlonly . -constexpr boost::process::detail::error_ error_code; - - -}} - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/exception.hpp b/include/boost/process/exception.hpp index 1bb391117..a9416db45 100644 --- a/include/boost/process/exception.hpp +++ b/include/boost/process/exception.hpp @@ -1,30 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 - -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_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/exe.hpp b/include/boost/process/exe.hpp index c9358c0a7..61383c95d 100644 --- a/include/boost/process/exe.hpp +++ b/include/boost/process/exe.hpp @@ -1,97 +1,9 @@ -// 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 +// Copyright (c) 2024 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 - -/** \file boost/process/exe.hpp - * - * Header which provides the exe property. -\xmlonly - -namespace boost { - namespace process { - unspecified exe; - } -} - -\endxmlonly - */ -namespace boost { -namespace filesystem { class path; } - -namespace process { - -namespace detail { - -struct exe_ -{ - template - inline exe_setter_ operator()(const boost::process::filesystem::path & pth) const - { - return exe_setter_(pth.native()); - } - - template - inline exe_setter_ operator=(const boost::process::filesystem::path & pth) const - { - return exe_setter_(pth.native()); - } - - - template - inline exe_setter_ operator()(const Char *s) const - { - return exe_setter_(s); - } - template - inline exe_setter_ operator= (const Char *s) const - { - return exe_setter_(s); - } - - template - inline exe_setter_ operator()(const std::basic_string &s) const - { - return exe_setter_(s); - } - template - inline exe_setter_ operator= (const std::basic_string &s) const - { - return exe_setter_(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::process::filesystem::path`. - -\code{.cpp} -exe="value"; -exe(value); -\endcode - -The property can only be used for assignments. - - - */ -constexpr boost::process::detail::exe_ exe{}; - -}} - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/extend.hpp b/include/boost/process/extend.hpp index 393573607..aaa0e8651 100644 --- a/include/boost/process/extend.hpp +++ b/include/boost/process/extend.hpp @@ -1,344 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include - -#if defined(BOOST_WINDOWS_API) -#include -#include -#include -#else -#include -#include -#include -#endif - - -/** \file boost/process/extend.hpp - * - * This header which provides the types and functions provided for custom extensions. - * - * \xmlonly - Please refer to the tutorial for more details. - \endxmlonly - */ - - -namespace boost { -namespace process { -namespace detail { -template -inline asio::io_context& get_io_context(const Tuple & tup); -} - - -///Namespace for extensions \attention This is experimental. -namespace extend { - -#if defined(BOOST_WINDOWS_API) - -template -using windows_executor = ::boost::process::detail::windows::executor; -template -struct posix_executor; - -#elif defined(BOOST_POSIX_API) - -template -using posix_executor = ::boost::process::detail::posix::executor; -template -struct windows_executor; - -#endif - -using ::boost::process::detail::handler; -using ::boost::process::detail::api::require_io_context; -using ::boost::process::detail::api::async_handler; -using ::boost::process::detail::get_io_context; -using ::boost::process::detail::get_last_error; -using ::boost::process::detail::throw_last_error; -using ::boost::process::detail::uses_handles; -using ::boost::process::detail::foreach_used_handle; -using ::boost::process::detail::get_used_handles; - -///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 on_setup; -///This handler is invoked if an error occurred. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter. -constexpr boost::process::detail::make_handler_t 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 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_context from the initializer sequence. - * - * \attention Yields a compile-time error if no `io_context` is provided. - * \param seq The Sequence of the initializer. - */ -template -inline asio::io_context& get_io_context(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 - 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 - 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 - 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 - 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 - 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 - void on_exec_error (Executor &, const std::error_code&) const {} - -}; - - -/** Inheriting the class will tell the launching process that an `io_context` is - * needed. This should always be used when \ref get_io_context is used. - * - */ -struct require_io_context {}; -/** 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_context. - * - * You must add the following function to your implementation: - * - \code{.cpp} -template -std::function on_exit_handler(Executor & exec) -{ - auto handler_ = this->handler; - return [handler_](int exit_code, const std::error_code & ec) - { - handler_(static_cast(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_context -{ - -}; - -///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) - - - - -The sequence if when no error occurs. - - - - - - - - -The sequence if the execution fails. - - - - - - - - -The sequence if the fork fails. - - - - - - -\endxmlonly - - -\note Error handling if execve fails is done through a pipe, unless \ref ignore_error is used. - - */ -template -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_context` and \ref child. - std::shared_ptr> exit_status = std::make_shared>(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) - - -The sequence for windows process creation. - - - - - -\endxmlonly - - */ - -template -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_context` and \ref child. - std::shared_ptr> exit_status = std::make_shared>(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::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::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 +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/filesystem.hpp b/include/boost/process/filesystem.hpp index 4e1c12e84..bb42d8e92 100644 --- a/include/boost/process/filesystem.hpp +++ b/include/boost/process/filesystem.hpp @@ -1,28 +1,9 @@ -// Copyright (c) 2021 Klemens D. Morgenstern +// Copyright (c) 2024 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_FILESYSTEM_HPP -#define BOOST_PROCESS_FILESYSTEM_HPP -#ifdef BOOST_PROCESS_USE_STD_FS -#include -#else -#include -#include -#endif -namespace boost -{ -namespace process -{ -#ifdef BOOST_PROCESS_USE_STD_FS -namespace filesystem = std::filesystem; -#else -namespace filesystem = boost::filesystem; -#endif - -} -} - -#endif //BOOST_PROCESS_FILESYSTEM_HPP +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/group.hpp b/include/boost/process/group.hpp index 7487f86ff..f441adf99 100644 --- a/include/boost/process/group.hpp +++ b/include/boost/process/group.hpp @@ -1,233 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include -#include - -#include -#include - - -#if defined(BOOST_POSIX_API) -#include -#include -#include -#elif defined(BOOST_WINDOWS_API) -#include -#include -#include -#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); - } -#if !defined(BOOST_PROCESS_NO_DEPRECATED) - /** 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 > - BOOST_DEPRECATED("wait_for is unreliable") - bool wait_for (const std::chrono::duration& rel_time) - { - return boost::process::detail::api::wait_for(_group_handle, rel_time); - } - - /** \overload bool wait_for(const std::chrono::duration& timeout_time ) */ - template< class Rep, class Period > - BOOST_DEPRECATED("wait_for is unreliable") - bool wait_for (const std::chrono::duration& 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 > - BOOST_DEPRECATED("wait_until is unreliable") - bool wait_until(const std::chrono::time_point& timeout_time ) - { - return boost::process::detail::api::wait_until(_group_handle, timeout_time); - } - /** \overload bool wait_until(const std::chrono::time_point& timeout_time ) */ - template< class Clock, class Duration > - BOOST_DEPRECATED("wait_until is unreliable") - bool wait_until(const std::chrono::time_point& timeout_time, std::error_code & ec) noexcept - { - return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec); - } -#endif - ///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 -{ - typedef group_tag type; -}; - -template<> -struct initializer_builder -{ - typedef group_builder type; -}; - -} -}} -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/handles.hpp b/include/boost/process/handles.hpp index cc65940dc..82a502109 100644 --- a/include/boost/process/handles.hpp +++ b/include/boost/process/handles.hpp @@ -1,107 +1,9 @@ -// Copyright (c) 2019 Klemens D. Morgenstern +// Copyright (c) 2024 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_HANDLES_HPP_ -#define BOOST_PROCESS_HANDLES_HPP_ -/** - * \file boost/process/handles.hpp - * - * Defines functions to obtain handles of the current process and limit the amount for inherited ones. - */ - -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -#include - - -namespace boost { namespace this_process -{ - -///The native type for handles -using native_handle_type = ::boost::process::detail::api::native_handle_type; - -/** - * Get a snapshot of all handles of the process (i.e. file descriptors on posix and handles on windows) of the current process. - * - * \note This function might not work on certain posix systems. - * - * \note On Windows version older than windows 8 this function will iterate all the system handles, meaning it might be quite slow. - * - * \warning This functionality is utterly prone to race conditions, since other threads might open or close handles. - * - * \return The list of all open handles of the current process - */ -inline std::vector get_handles() -{ - return ::boost::process::detail::api::get_handles(); -} - - -/** \overload std::vector get_handles() */ -inline std::vector get_handles(std::error_code &ec) -{ - return ::boost::process::detail::api::get_handles(ec); -} - -/** Determines if a given handle is a a stream-handle, i.e. any handle that can be used with read and write functions. - * Stream handles include pipes, regular files and sockets. - * - * \return Indicates if it's a stream handle. - */ -inline bool is_stream_handle(native_handle_type handle) -{ - return ::boost::process::detail::api::is_stream_handle(handle); -} - - -/** \overload bool is_stream_handle(native_handle_type handle) */ -inline bool is_stream_handle(native_handle_type handle, std::error_code &ec) -{ - return ::boost::process::detail::api::is_stream_handle(handle, ec); -} - -} -namespace process -{ - -namespace detail -{ - -using limit_handles_ = ::boost::process::detail::api::limit_handles_; - - -} - -/** - * The limit_handles property sets all properties to be inherited only explicitly. It closes all unused file-descriptors on posix after the fork and - * removes the inherit flags on windows. - * - * \note This is executed after the fork on posix. - * - * \code{.cpp} - * system("gcc", limit_handles); - * \endcode - * - * Since limit also closes the standard handles unless they are explicitly redirected they can be ignored by `limit_handles` in the following way. - * - * \code{.cpp} - * system("gcc", limit_handles.allowStd()) - * \endcode - * -*/ -const static ::boost::process::detail::api::limit_handles_ limit_handles; - - -} -} - -#endif //BOOST_PROCESS_HANDLES_HPP_ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/io.hpp b/include/boost/process/io.hpp index 8238de686..665354597 100644 --- a/include/boost/process/io.hpp +++ b/include/boost/process/io.hpp @@ -1,551 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include -#include -#include -#include - -#include - -#if defined(BOOST_POSIX_API) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#elif defined(BOOST_WINDOWS_API) -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -/** \file boost/process/io.hpp - * - * Header which provides the io properties. It provides the following properties: - * -\xmlonly - -namespace boost { - namespace process { - unspecified close; - unspecified null; - unspecified std_in; - unspecified std_out; - unspecified std_err; - } -} - -\endxmlonly - -\par File I/O - -The library allows full redirection of streams to files as shown below. - -\code{.cpp} -boost::process::filesystem::path log = "my_log_file.txt"; -boost::process::filesystem::path input = "input.txt"; -boost::process::filesystem::path output = "output.txt"; -system("my_prog", std_out>output, std_inlog); -\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 output; -system("ls", std_out > output, ios); - -auto res = fut.get(); -\endcode - -\note `boost/process/async.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 using is_streambuf = typename std::is_same::type; -template using is_const_buffer = - std::integral_constant::value | - std::is_base_of::value - >; -template using is_mutable_buffer = - std::integral_constant::value | - std::is_base_of::value - >; - - -struct null_t {constexpr null_t() = default;}; -struct close_t; - -template -struct std_in_ -{ - constexpr std_in_() = default; - - 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::process::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::process::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 api::pipe_in operator=(basic_pipe & p) const {return p;} - template api::pipe_in operator<(basic_pipe & p) const {return p;} - template api::pipe_in operator=(basic_opstream & p) const {return p.pipe();} - template api::pipe_in operator<(basic_opstream & p) const {return p.pipe();} - template api::pipe_in operator=(basic_pstream & p) const {return p.pipe();} - template api::pipe_in operator<(basic_pstream & 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::value || is_mutable_buffer::value - >::type> - api::async_in_buffer operator=(const T & buf) const {return buf;} - template::value>::type > - api::async_in_buffer operator=(T & buf) const {return buf;} - - template::value || is_mutable_buffer::value - >::type> - api::async_in_buffer operator<(const T & buf) const {return buf;} - template::value>::type > - api::async_in_buffer operator<(T & buf) const {return buf;} - -}; - -//-1 == empty. -//1 == stdout -//2 == stderr -template -struct std_out_ -{ - constexpr std_out_() = default; - - api::close_out close() const {return api::close_out(); } - api::close_out operator=(const close_t &) const {return api::close_out();} - api::close_out operator>(const close_t &) const {return api::close_out();} - - api::null_out null() const {return api::null_out();} - api::null_out operator=(const null_t &) const {return api::null_out();} - api::null_out operator>(const null_t &) const {return api::null_out();} - - api::file_out operator=(const boost::process::filesystem::path &p) const {return api::file_out(p);} - api::file_out operator=(const std::string &p) const {return api::file_out(p);} - api::file_out operator=(const std::wstring &p) const {return api::file_out(p);} - api::file_out operator=(const char * p) const {return api::file_out(p);} - api::file_out operator=(const wchar_t * p) const {return api::file_out(p);} - - api::file_out operator>(const boost::process::filesystem::path &p) const {return api::file_out(p);} - api::file_out operator>(const std::string &p) const {return api::file_out(p);} - api::file_out operator>(const std::wstring &p) const {return api::file_out(p);} - api::file_out operator>(const char * p) const {return api::file_out(p);} - api::file_out operator>(const wchar_t * p) const {return api::file_out(p);} - - api::file_out operator=(FILE * f) const {return f;} - api::file_out operator>(FILE * f) const {return f;} - - template api::pipe_out operator=(basic_pipe & p) const {return p;} - template api::pipe_out operator>(basic_pipe & p) const {return p;} - template api::pipe_out operator=(basic_ipstream & p) const {return p.pipe();} - template api::pipe_out operator>(basic_ipstream & p) const {return p.pipe();} - template api::pipe_out operator=(basic_pstream & p) const {return p.pipe();} - template api::pipe_out operator>(basic_pstream & p) const {return p.pipe();} - - api::async_pipe_out operator=(async_pipe & p) const {return p;} - api::async_pipe_out operator>(async_pipe & p) const {return p;} - - api::async_out_buffer operator=(const asio::mutable_buffer & buf) const {return buf;} - api::async_out_buffer operator=(const asio::mutable_buffers_1 & buf) const {return buf;} - api::async_out_buffer operator=(asio::streambuf & os) const {return os ;} - - api::async_out_buffer operator>(const asio::mutable_buffer & buf) const {return buf;} - api::async_out_buffer operator>(const asio::mutable_buffers_1 & buf) const {return buf;} - api::async_out_buffer operator>(asio::streambuf & os) const {return os ;} - - api::async_out_future operator=(std::future & fut) const { return fut;} - api::async_out_future operator>(std::future & fut) const { return fut;} - api::async_out_future> operator=(std::future> & fut) const { return fut;} - api::async_out_future> operator>(std::future> & fut) const { return fut;} - - template::type> - constexpr std_out_<1, 2> operator& (const std_out_&) const - { - return std_out_<1, 2> (); - } - -}; - -struct close_t -{ - constexpr close_t() = default; - template - api::close_out operator()(std_out_) {return api::close_out();} -}; - - - -} -///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::process::filesystem::path` - - `std::basic_string` - - `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 Constructed with boost::asio::buffer \endxmlonly - - `boost::asio::mutable_buffer` \xmlonly Constructed with boost::asio::buffer \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` onto it, -so you can wait for the input to be completed. It looks like this: -\code{.cpp} -std::future fut; -boost::asio::io_context 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_context` 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_ std_in; - -/** -This property allows to set the output stream for the child process. - -\note The Semantic is the same as for \xmlonly std_err \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::process::filesystem::path` - - `std::basic_string` - - `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 Constructed with boost::asio::buffer \endxmlonly - - `boost::asio::streambuf` - - `std::future>` - - `std::future` - -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_context` 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 std_out \endxmlonly . - */ -constexpr boost::process::detail::std_out_<2> std_err; - -}} -#endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/locale.hpp b/include/boost/process/locale.hpp index fda911285..cd741c753 100644 --- a/include/boost/process/locale.hpp +++ b/include/boost/process/locale.hpp @@ -1,245 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern -// Copyright (c) 2008 Beman Dawes +// Copyright (c) 2024 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_LOCALE_HPP_ -#define BOOST_PROCESS_LOCALE_HPP_ -#include -#include - -#if defined(BOOST_WINDOWS_API) -#include -# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \ -|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__) -#include -#endif - -#include - -namespace boost -{ -namespace process -{ -namespace detail -{ - -class codecvt_category_t : public std::error_category -{ -public: - codecvt_category_t() = default; - 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); -# else // Other POSIX - // Return a default locale object. - 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 codecvt_type; - -///Get a reference to the currently used code converter. -inline const codecvt_type& codecvt() -{ - return std::use_facet>( - 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 convert(const std::vector & st, - const ::boost::process::codecvt_type & cvt = - ::boost::process::codecvt()) -{ - std::vector 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 convert(const std::vector & st, - const ::boost::process::codecvt_type & cvt = - ::boost::process::codecvt()) -{ - std::vector 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_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/pipe.hpp b/include/boost/process/pipe.hpp index e20725ed2..0cf85bc9b 100644 --- a/include/boost/process/pipe.hpp +++ b/include/boost/process/pipe.hpp @@ -1,631 +1,9 @@ -// 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) 2024 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_PIPE_HPP -#define BOOST_PROCESS_PIPE_HPP - -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#endif - -namespace boost { namespace process { - -using ::boost::process::detail::api::basic_pipe; - -#if defined(BOOST_PROCESS_DOXYGEN) -/** Class implementation of a pipe. - * - */ -template> -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 pipe; -typedef basic_pipe wpipe; - - -/** Implementation of the stream buffer for a pipe. - */ -template< - class CharT, - class Traits = std::char_traits -> -struct basic_pipebuf : std::basic_streambuf -{ - typedef basic_pipe 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; - - ///Destructor -> writes the frest of the data - ~basic_pipebuf() - { - try - { - if (basic_pipebuf::is_open()) - basic_pipebuf::overflow(Traits::eof()); - } - catch (process_error & ) - { - } - } - - ///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 (_pipe.is_open() && (ch != traits_type::eof())) - { - if (this->pptr() == this->epptr()) - { - bool wr = this->_write_impl(); - if (wr) - { - *this->pptr() = ch; - this->pbump(1); - return ch; - } - } - else - { - *this->pptr() = ch; - this->pbump(1); - if (this->_write_impl()) - return ch; - } - } - else if (ch == traits_type::eof()) - this->sync(); - - 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(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);} - - ///Check if the pipe is open - bool is_open() const {return _pipe.is_open(); } - - ///Open a new pipe - basic_pipebuf* open() - { - if (is_open()) - return nullptr; - _pipe = pipe(); - return this; - } - - ///Open a new named pipe - basic_pipebuf* open(const std::string & name) - { - if (is_open()) - return nullptr; - _pipe = pipe(name); - return this; - } - - ///Flush the buffer & close the pipe - basic_pipebuf* close() - { - if (!is_open()) - return nullptr; - overflow(Traits::eof()); - return this; - } -private: - pipe_type _pipe; - std::vector _write; - std::vector _read; - - bool _write_impl() - { - if (!_pipe.is_open()) - return false; - - auto base = this->pbase(); - - if (base == this->pptr()) - return true; - - std::ptrdiff_t wrt = _pipe.write(base, - static_cast(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(static_cast(-wrt)); - - return true; - } -}; - -typedef basic_pipebuf pipebuf; -typedef basic_pipebuf wpipebuf; - -/** Implementation of a reading pipe stream. - * - */ -template< - class CharT, - class Traits = std::char_traits -> -class basic_ipstream : public std::basic_istream -{ - mutable basic_pipebuf _buf; -public: - - typedef basic_pipe 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* rdbuf() const {return &_buf;}; - - ///Default constructor. - basic_ipstream() : std::basic_istream(nullptr) - { - std::basic_istream::rdbuf(&_buf); - }; - ///Copy constructor. - basic_ipstream(const basic_ipstream & ) = delete; - ///Move constructor. - basic_ipstream(basic_ipstream && lhs) : std::basic_istream(nullptr), _buf(std::move(lhs._buf)) - { - std::basic_istream::rdbuf(&_buf); - } - - ///Move construct from a pipe. - basic_ipstream(pipe_type && p) : std::basic_istream(nullptr), _buf(std::move(p)) - { - std::basic_istream::rdbuf(&_buf); - } - - ///Copy construct from a pipe. - basic_ipstream(const pipe_type & p) : std::basic_istream(nullptr), _buf(p) - { - std::basic_istream::rdbuf(&_buf); - } - - ///Copy assignment. - basic_ipstream& operator=(const basic_ipstream & ) = delete; - ///Move assignment - basic_ipstream& operator=(basic_ipstream && lhs) - { - std::basic_istream::operator=(std::move(lhs)); - _buf = std::move(lhs._buf); - std::basic_istream::rdbuf(&_buf); - return *this; - }; - ///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();} - ///Check if the pipe is open - bool is_open() const {return _buf.is_open();} - - ///Open a new pipe - void open() - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Open a new named pipe - void open(const std::string & name) - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Flush the buffer & close the pipe - void close() - { - if (_buf.close() == nullptr) - this->setstate(std::ios_base::failbit); - } -}; - -typedef basic_ipstream ipstream; -typedef basic_ipstream wipstream; - -/** Implementation of a write pipe stream. - * - */ -template< - class CharT, - class Traits = std::char_traits -> -class basic_opstream : public std::basic_ostream -{ - mutable basic_pipebuf _buf; -public: - typedef basic_pipe 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* rdbuf() const {return &_buf;}; - - ///Default constructor. - basic_opstream() : std::basic_ostream(nullptr) - { - std::basic_ostream::rdbuf(&_buf); - }; - ///Copy constructor. - basic_opstream(const basic_opstream & ) = delete; - ///Move constructor. - basic_opstream(basic_opstream && lhs) : std::basic_ostream(nullptr), _buf(std::move(lhs._buf)) - { - std::basic_ostream::rdbuf(&_buf); - } - ///Move construct from a pipe. - basic_opstream(pipe_type && p) : std::basic_ostream(nullptr), _buf(std::move(p)) - { - std::basic_ostream::rdbuf(&_buf); - }; - ///Copy construct from a pipe. - basic_opstream(const pipe_type & p) : std::basic_ostream(nullptr), _buf(p) - { - std::basic_ostream::rdbuf(&_buf); - }; - ///Copy assignment. - basic_opstream& operator=(const basic_opstream & ) = delete; - ///Move assignment - basic_opstream& operator=(basic_opstream && lhs) - { - std::basic_ostream::operator=(std::move(lhs)); - _buf = std::move(lhs._buf); - std::basic_ostream::rdbuf(&_buf); - return *this; - }; - - ///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();} - - ///Open a new pipe - void open() - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Open a new named pipe - void open(const std::string & name) - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Flush the buffer & close the pipe - void close() - { - if (_buf.close() == nullptr) - this->setstate(std::ios_base::failbit); - } -}; - -typedef basic_opstream opstream; -typedef basic_opstream wopstream; - - -/** Implementation of a read-write pipe stream. - * - */ -template< - class CharT, - class Traits = std::char_traits -> -class basic_pstream : public std::basic_iostream -{ - mutable basic_pipebuf _buf; -public: - typedef basic_pipe 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* rdbuf() const {return &_buf;}; - - ///Default constructor. - basic_pstream() : std::basic_iostream(nullptr) - { - std::basic_iostream::rdbuf(&_buf); - }; - ///Copy constructor. - basic_pstream(const basic_pstream & ) = delete; - ///Move constructor. - basic_pstream(basic_pstream && lhs) : std::basic_iostream(nullptr), _buf(std::move(lhs._buf)) - { - std::basic_iostream::rdbuf(&_buf); - } - ///Move construct from a pipe. - basic_pstream(pipe_type && p) : std::basic_iostream(nullptr), _buf(std::move(p)) - { - std::basic_iostream::rdbuf(&_buf); - }; - ///Copy construct from a pipe. - basic_pstream(const pipe_type & p) : std::basic_iostream(nullptr), _buf(p) - { - std::basic_iostream::rdbuf(&_buf); - }; - ///Copy assignment. - basic_pstream& operator=(const basic_pstream & ) = delete; - ///Move assignment - basic_pstream& operator=(basic_pstream && lhs) - { - std::basic_istream::operator=(std::move(lhs)); - _buf = std::move(lhs._buf); - std::basic_iostream::rdbuf(&_buf); - return *this; - }; - ///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();} - - ///Open a new pipe - void open() - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Open a new named pipe - void open(const std::string & name) - { - if (_buf.open() == nullptr) - this->setstate(std::ios_base::failbit); - else - this->clear(); - } - - ///Flush the buffer & close the pipe - void close() - { - if (_buf.close() == nullptr) - this->setstate(std::ios_base::failbit); - } -}; - -typedef basic_pstream pstream; -typedef basic_pstream wpstream; - - - -}} - - - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/posix.hpp b/include/boost/process/posix.hpp index 4c3035eb1..ce1d8e60d 100644 --- a/include/boost/process/posix.hpp +++ b/include/boost/process/posix.hpp @@ -1,75 +1,9 @@ -// Copyright (c) 2016 Klemens D. Morgenstern +// Copyright (c) 2024 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 -#include -#include -#include - -/** \file boost/process/posix.hpp - * - * Header which provides the posix extensions. -\xmlonly - -namespace boost { - namespace process { - namespace posix { - unspecified fd; - unspecified sig; - unspecified use_vfork; - } - } -} - - * \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 extensions. -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_ */ +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/search_path.hpp b/include/boost/process/search_path.hpp index 7e33ec552..4a8690255 100644 --- a/include/boost/process/search_path.hpp +++ b/include/boost/process/search_path.hpp @@ -1,54 +1,9 @@ -// 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) 2024 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/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 -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#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 to search, defaults to the "PATH" environment variable. - * - * \returns the absolute path to the executable filename or an - * empty string if filename isn't found - */ -inline boost::process::filesystem::path search_path(const boost::process::filesystem::path &filename, - const std::vector path = ::boost::this_process::path()) -{ - return ::boost::process::detail::api::search_path(filename, path); -} -}} - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/shell.hpp b/include/boost/process/shell.hpp index 87313d53f..218aa34f6 100644 --- a/include/boost/process/shell.hpp +++ b/include/boost/process/shell.hpp @@ -1,92 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include - -#if defined(BOOST_POSIX_API) -#include -#elif defined(BOOST_WINDOWS_API) -#include -#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 - -namespace boost { - namespace process { - unspecified shell; - } -} - -\endxmlonly - - */ - -namespace boost { namespace process { namespace detail { - - -struct shell_ -{ - constexpr shell_() {} - - boost::process::filesystem::path operator()() const - { - return boost::process::detail::api::shell_path(); - } - boost::process::filesystem::path operator()(std::error_code & ec) const noexcept - { - return boost::process::detail::api::shell_path(ec); - } -}; - -template<> -struct is_wchar_t : is_wchar_t -{ -}; - -} -/** -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 +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/spawn.hpp b/include/boost/process/spawn.hpp index 70ada3ed1..2d48987bc 100644 --- a/include/boost/process/spawn.hpp +++ b/include/boost/process/spawn.hpp @@ -1,69 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#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_context` is passed. - - */ -template -inline void spawn(Args && ...args) -{ - typedef typename ::boost::process::detail::has_async_handler::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)...); - c.detach(); -} - -}} -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/start_dir.hpp b/include/boost/process/start_dir.hpp index 49f4354a8..1fc31b436 100644 --- a/include/boost/process/start_dir.hpp +++ b/include/boost/process/start_dir.hpp @@ -1,111 +1,9 @@ -// 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) 2024 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_START_IN_DIR_HPP -#define BOOST_PROCESS_START_IN_DIR_HPP -#include -#include -#include -#include - -#if defined (BOOST_POSIX_API) -#include -#elif defined (BOOST_WINDOWS_API) -#include -#endif - -#include -#include -#include - -/** \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 - -namespace boost { - namespace process { - unspecified start_dir; - } -} - -\endxmlonly - - */ - -namespace boost { namespace process { namespace detail { - -struct start_dir_ -{ - constexpr start_dir_() {}; - - template - api::start_dir_init operator()(const std::basic_string & st) const {return {st}; } - template - api::start_dir_init operator()(std::basic_string && s) const {return {std::move(s)}; } - template - api::start_dir_init operator()(const Char* s) const {return {s}; } - api::start_dir_init - operator()(const boost::process::filesystem::path & st) const {return {st.native()}; } - - template - api::start_dir_init operator= (const std::basic_string & st) const {return {st}; } - template - api::start_dir_init operator= (std::basic_string && s) const {return {std::move(s)}; } - template - api::start_dir_init operator= (const Char* s) const {return {s}; } - api::start_dir_init - operator= (const boost::process::filesystem::path & st) const {return {st.native()}; } - -}; - -template<> struct is_wchar_t> : std::true_type {}; - -template<> -struct char_converter> -{ - static api::start_dir_init conv(const api::start_dir_init & in) - { - return api::start_dir_init{::boost::process::detail::convert(in.str())}; - } -}; - -template<> -struct char_converter> -{ - static api::start_dir_init conv(const api::start_dir_init & in) - { - return api::start_dir_init{::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::process::filesystem::path`. - - - */ -constexpr ::boost::process::detail::start_dir_ start_dir; - -}} - -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/system.hpp b/include/boost/process/system.hpp index 6cf48f265..3fd073791 100644 --- a/include/boost/process/system.hpp +++ b/include/boost/process/system.hpp @@ -1,157 +1,9 @@ -// 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 +// Copyright (c) 2024 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(BOOST_POSIX_API) -#include -#endif - -namespace boost { - -namespace process { - -namespace detail -{ - -struct system_impl_success_check : handler -{ - bool succeeded = false; - - template - void on_success(Exec &) { succeeded = true; } -}; - -template -inline int system_impl( - std::true_type, /*needs ios*/ - std::true_type, /*has io_context*/ - Args && ...args) -{ - IoService & ios = ::boost::process::detail::get_io_context_var(args...); - - system_impl_success_check check; - - std::atomic_bool exited{false}; - - child c(std::forward(args)..., - check, - ::boost::process::on_exit( - [&](int, const std::error_code&) - { - boost::asio::post(ios.get_executor(), [&]{exited.store(true);}); - })); - if (!c.valid() || !check.succeeded) - return -1; - - while (!exited.load()) - ios.poll(); - - return c.exit_code(); -} - -template -inline int system_impl( - std::true_type, /*needs ios */ - std::false_type, /*has io_context*/ - Args && ...args) -{ - IoService ios; - child c(ios, std::forward(args)...); - if (!c.valid()) - return -1; - - ios.run(); - if (c.running()) - c.wait(); - return c.exit_code(); -} - - -template -inline int system_impl( - std::false_type, /*needs ios*/ - std::true_type, /*has io_context*/ - Args && ...args) -{ - child c(std::forward(args)...); - if (!c.valid()) - return -1; - c.wait(); - return c.exit_code(); -} - -template -inline int system_impl( - std::false_type, /*has async */ - std::false_type, /*has io_context*/ - Args && ...args) -{ - child c(std::forward(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_context object, -the system function will create one and run it. When the io_context is passed to the function, -the system function will check if it is active, and call the io_context::run function if not. - -*/ -template -inline int system(Args && ...args) -{ - typedef typename ::boost::process::detail::needs_io_context::type - need_ios; - typedef typename ::boost::process::detail::has_io_context::type - has_ios; - return ::boost::process::detail::system_impl( - need_ios(), has_ios(), - std::forward(args)...); -} - - -}} -#endif +#include +BOOST_HEADER_DEPRECATED("") +#include diff --git a/include/boost/process/v1.hpp b/include/boost/process/v1.hpp new file mode 100644 index 000000000..9d081cda6 --- /dev/null +++ b/include/boost/process/v1.hpp @@ -0,0 +1,28 @@ +// Copyright (c) 2024 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_V1_HPP +#define BOOST_PROCESS_V1_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif //BOOST_PROCESS_V1_HPP diff --git a/include/boost/process/v1/args.hpp b/include/boost/process/v1/args.hpp new file mode 100644 index 000000000..b06ca624c --- /dev/null +++ b/include/boost/process/v1/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 args\endxmlonly property. It also provides the + * alternative name \xmlonly argv\endxmlonly . + * + * +\xmlonly + +namespace boost { + namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { + unspecified args; + unspecified argv; + } +} + +\endxmlonly + */ + + +#include +#include + +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { + +struct args_ +{ + template + using remove_reference_t = typename std::remove_reference::type; + template + using value_type = typename remove_reference_t::value_type; + + template + using vvalue_type = value_type>; + + template + arg_setter_, true> operator()(Range &&range) const + { + return arg_setter_, true>(std::forward(range)); + } + template + arg_setter_, true> operator+=(Range &&range) const + { + return arg_setter_, true>(std::forward(range)); + } + template + arg_setter_, false> operator= (Range &&range) const + { + return arg_setter_, false>(std::forward(range)); + } + template + arg_setter_ operator()(std::basic_string && str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator+=(std::basic_string && str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator= (std::basic_string && str) const + { + return arg_setter_(str); + } + template + arg_setter_ operator()(const std::basic_string & str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator+=(const std::basic_string & str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator= (const std::basic_string & str) const + { + return arg_setter_(str); + } + template + arg_setter_ operator()(std::basic_string & str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator+=(std::basic_string & str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator= (std::basic_string & str) const + { + return arg_setter_(str); + } + template + arg_setter_ operator()(const Char* str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator+=(const Char* str) const + { + return arg_setter_ (str); + } + template + arg_setter_ operator= (const Char* str) const + { + return arg_setter_(str); + } +// template +// arg_setter_ operator()(const Char (&str) [Size]) const +// { +// return arg_setter_ (str); +// } +// template +// arg_setter_ operator+=(const Char (&str) [Size]) const +// { +// return arg_setter_ (str); +// } +// template +// arg_setter_ operator= (const Char (&str) [Size]) const +// { +// return arg_setter_(str); +// } + + arg_setter_ operator()(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator+=(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator= (std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator()(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator+=(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator= (std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + + arg_setter_ operator()(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator+=(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator= (std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator()(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator+=(std::initializer_list &&range) const + { + return arg_setter_(range.begin(), range.end()); + } + arg_setter_ operator= (std::initializer_list &&range) const + { + return arg_setter_(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` + - `const char_type * ` + - `std::initializer_list` + - `std::vector>` + +Additionally any range of `std::basic_string` 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` + - `const char_type * ` + - `std::initializer_list` + - `std::vector>` + +Additionally any range of `std::basic_string` 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::v1::detail::args_ args{}; + +///Alias for \xmlonly args \endxmlonly . +constexpr boost::process::v1::detail::args_ argv{}; + + +}}} + +#endif diff --git a/include/boost/process/v1/async.hpp b/include/boost/process/v1/async.hpp new file mode 100644 index 000000000..d701d921f --- /dev/null +++ b/include/boost/process/v1/async.hpp @@ -0,0 +1,134 @@ +// 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 asynchronous 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_context, +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 + +namespace boost { + namespace process { + namespace v1 { + unspecified buffer; + unspecified on_exit; + } + } +} + + +\endxmlonly + */ + +#ifndef BOOST_PROCESS_ASYNC_HPP_ +#define BOOST_PROCESS_ASYNC_HPP_ + +#include +#include + +#include +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#include +#include +#include + +#elif defined(BOOST_WINDOWS_API) +#include +#include +#include +#include +#endif + +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { + +struct async_tag; + +template +struct is_io_context : std::false_type {}; +template<> +struct is_io_context : std::true_type {}; + +template +inline asio::io_context& get_io_context(const Tuple & tup) +{ + auto& ref = *boost::fusion::find_if>(tup); + return ref.get(); +} + +struct async_builder +{ + boost::asio::io_context * ios; + + void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;}; + + typedef api::io_context_ref result_type; + api::io_context_ref get_initializer() {return api::io_context_ref (*ios);}; +}; + + +template<> +struct initializer_builder +{ + typedef async_builder type; +}; + +} + +using ::boost::asio::buffer; + + +#if defined(BOOST_PROCESS_DOXYGEN) +/** When an io_context 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`. + +\par Example + +\code{.cpp} +io_context ios; + +child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){}); + +std::future exit_code; +chlid c2("ls", ios, on_exit=exit_code); + +\endcode + +\note The handler is not invoked when the launch fails. +\warning When used \ref ignore_error it might get invoked on error. +\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the +same restrictions as that class (do not register a handler for `SIGCHLD` except by using +`boost::asio::signal_set`). + */ +constexpr static ::boost::process::v1::detail::on_exit_ on_exit{}; +#endif + +}}} + + + +#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */ diff --git a/include/boost/process/v1/async_pipe.hpp b/include/boost/process/v1/async_pipe.hpp new file mode 100644 index 000000000..642c18943 --- /dev/null +++ b/include/boost/process/v1/async_pipe.hpp @@ -0,0 +1,217 @@ +// 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 +#include + +#if defined(BOOST_POSIX_API) +#include +#elif defined(BOOST_WINDOWS_API) +#include +#endif + +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { + + +#if defined(BOOST_PROCESS_DOXYGEN) + + +/** Class implementing an 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; + + typedef typename handle_type::executor_type executor_type; + + /** Construct a new async_pipe, does automatically open the pipe. + * Initializes source and sink with the same io_context. + * @note Windows creates a named pipe here, where the name is automatically generated. + */ + inline async_pipe(boost::asio::io_context & 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_context & ios_source, + boost::asio::io_context & ios_sink); + + /** Construct a new async_pipe, does automatically open. + * Initializes source and sink with the same io_context. + * + * @note Windows restricts possible names. + */ + inline async_pipe(boost::asio::io_context & ios, const std::string & name); + + + /** Construct a new async_pipe, does automatically open. + * + * @note Windows restricts possible names. + */ + inline async_pipe(boost::asio::io_context & ios_source, + boost::asio::io_context & 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> + explicit async_pipe(boost::asio::io_context & ios, const basic_pipe & p); + + /** Construct the async-pipe from a pipe, with two different io_context objects. + * @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown. + * + */ + template> + explicit async_pipe(boost::asio::io_context & ios_source, + boost::asio::io_context & ios_sink, + const basic_pipe & 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> + inline async_pipe& operator=(const basic_pipe& 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> + inline explicit operator basic_pipe() 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 + std::size_t read_some(const MutableBufferSequence & buffers); + + /** Write some data to the handle. + + * See the boost.asio documentation for more details. + */ + template + std::size_t write_some(const MutableBufferSequence & buffers); + + /** Get the native handle of the source. */ + native_handle native_source() const {return const_cast(_source).native();} + /** Get the native handle of the sink. */ + native_handle native_sink () const {return const_cast(_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 + 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 + 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_context. Qualified as rvalue. \attention Will always move. + handle_type source(::boost::asio::io_context& ios) &&; + /// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move + handle_type sink (::boost::asio::io_context& ios) &&; + + /// Copy the source out of this class and change the io_context. \attention Will always copy. + handle_type source(::boost::asio::io_context& ios) const &; + /// Copy the sink out of this class and change the io_context. \attention Will always copy + handle_type sink (::boost::asio::io_context& ios) const &; + + + +}; + +#else +using ::boost::process::v1::detail::api::async_pipe; +#endif + + +}}} + + + +#endif diff --git a/include/boost/process/v1/async_system.hpp b/include/boost/process/v1/async_system.hpp new file mode 100644 index 000000000..830a19b82 --- /dev/null +++ b/include/boost/process/v1/async_system.hpp @@ -0,0 +1,151 @@ +// 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 asynchronous version of the system function. + */ + +#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP +#define BOOST_PROCESS_ASYNC_SYSTEM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#endif + +namespace boost { +namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { +namespace detail +{ + +template +struct async_system_handler : ::boost::process::v1::detail::api::async_handler +{ + boost::asio::io_context & ios; + Handler handler; + +#if defined(BOOST_POSIX_API) + bool errored = false; +#endif + + template + async_system_handler( + boost::asio::io_context & ios, + ExitHandler_ && exit_handler) : ios(ios), handler(std::forward(exit_handler)) + { + } + + + template + void on_error(Exec&, const std::error_code & ec) + { +#if defined(BOOST_POSIX_API) + errored = true; +#endif + auto h = std::make_shared(std::move(handler)); + boost::asio::post( + ios.get_executor(), + [h, ec]() mutable + { + (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1); + }); + } + + template + std::function on_exit_handler(Executor&) + { +#if defined(BOOST_POSIX_API) + if (errored) + return [](int , const std::error_code &){}; +#endif + auto h = std::make_shared(std::move(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 +struct is_error_handler> : 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_context](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 +inline boost::process::v1::detail::dummy + async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args); +#endif + +namespace detail +{ +struct async_system_init_op +{ + + template + void operator()(Handler && handler, asio::io_context & ios, Args && ... args) + { + detail::async_system_handler::type> async_h{ios, std::forward(handler)}; + child(ios, std::forward(args)..., async_h ).detach(); + } +}; + + +} + + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) + async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args) +{ + + typedef typename ::boost::process::v1::detail::has_error_handler>::type + has_err_handling; + + static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); + + return boost::asio::async_initiate( + detail::async_system_init_op{}, exit_handler, ios, std::forward(args)... + ); +} + + + +}}} + +#endif diff --git a/include/boost/process/v1/child.hpp b/include/boost/process/v1/child.hpp new file mode 100644 index 000000000..ee0c4f726 --- /dev/null +++ b/include/boost/process/v1/child.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/child.hpp + * + * Defines a child process class. + */ + +#ifndef BOOST_PROCESS_CHILD_HPP +#define BOOST_PROCESS_CHILD_HPP + +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#endif + +namespace boost { + +///The main namespace of boost.process. +namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { + +template +child::child(Args&&...args) + : child(::boost::process::v1::detail::execute_impl(std::forward(args)...)) {} + + +///Typedef for the type of an pid_t +typedef ::boost::process::v1::detail::api::pid_t pid_t; + +#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 + 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; + + /** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited + * for or if it was terminated. */ + int native_exit_code() 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& rel_time); + /** \overload bool wait_for(const std::chrono::duration& rel_time) */ + bool wait_for (const std::chrono::duration& 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& timeout_time ); + /** \overload bool wait_until(const std::chrono::time_point& timeout_time )*/ + bool wait_until(const std::chrono::time_point& 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/include/boost/process/v1/cmd.hpp b/include/boost/process/v1/cmd.hpp new file mode 100644 index 000000000..7b36eba65 --- /dev/null +++ b/include/boost/process/v1/cmd.hpp @@ -0,0 +1,121 @@ +// 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 +#include +#include +#include +#include + +#if defined(BOOST_POSIX_API) +#include +#elif defined(BOOST_WINDOWS_API) +#include +#endif + +/** \file boost/process/cmd.hpp + * + * This header provides the \xmlonly cmd\endxmlonly property. + * +\xmlonly + +namespace boost { + namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { + unspecified cmd; + } +} + +\endxmlonly +*/ + +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { + + +struct cmd_ +{ + constexpr cmd_() = default; + + template + inline api::cmd_setter_ operator()(const Char *s) const + { return api::cmd_setter_(s); + } + template + inline api::cmd_setter_ operator= (const Char *s) const + { + return api::cmd_setter_(s); + } + + template + inline api::cmd_setter_ operator()(const std::basic_string &s) const + { + return api::cmd_setter_(s); + } + template + inline api::cmd_setter_ operator= (const std::basic_string &s) const + { + return api::cmd_setter_(s); + } +}; + +template<> struct is_wchar_t> : std::true_type {}; + + + +template<> +struct char_converter> +{ + static api::cmd_setter_ conv(const api::cmd_setter_ & in) + { + return { ::boost::process::v1::detail::convert(in.str()) }; + } +}; + +template<> +struct char_converter> +{ + static api::cmd_setter_ conv(const api::cmd_setter_ & in) + { + return { ::boost::process::v1::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::v1::detail::cmd_ cmd; + +}}} + +#endif diff --git a/include/boost/process/detail/async_handler.hpp b/include/boost/process/v1/detail/async_handler.hpp similarity index 79% rename from include/boost/process/detail/async_handler.hpp rename to include/boost/process/v1/detail/async_handler.hpp index b4eaf9349..99601daeb 100644 --- a/include/boost/process/detail/async_handler.hpp +++ b/include/boost/process/v1/detail/async_handler.hpp @@ -11,26 +11,26 @@ #include #if defined(BOOST_POSIX_API) -#include -#include -#include +#include +#include +#include #else -#include -#include +#include +#include #endif namespace boost { -namespace process { +namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { #if defined(BOOST_POSIX_API) -using ::boost::process::detail::posix::is_async_handler; -using ::boost::process::detail::posix::does_require_io_context; +using ::boost::process::v1::detail::posix::is_async_handler; +using ::boost::process::v1::detail::posix::does_require_io_context; #else -using ::boost::process::detail::windows::is_async_handler; -using ::boost::process::detail::windows::does_require_io_context; +using ::boost::process::v1::detail::windows::is_async_handler; +using ::boost::process::v1::detail::windows::does_require_io_context; #endif template @@ -112,6 +112,7 @@ boost::asio::io_context &get_io_context_var(First&, Args&...args) } } } +} #endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */ diff --git a/include/boost/process/detail/basic_cmd.hpp b/include/boost/process/v1/detail/basic_cmd.hpp similarity index 87% rename from include/boost/process/detail/basic_cmd.hpp rename to include/boost/process/v1/detail/basic_cmd.hpp index f3405bbb1..8064978af 100644 --- a/include/boost/process/detail/basic_cmd.hpp +++ b/include/boost/process/v1/detail/basic_cmd.hpp @@ -7,26 +7,26 @@ #ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_ #define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_ -#include +#include -#include -#include -#include +#include +#include +#include #if defined( BOOST_WINDOWS_API ) -#include -#include +#include +#include #elif defined( BOOST_POSIX_API ) -#include -#include +#include +#include #endif -#include +#include #include -namespace boost { namespace process { namespace detail { +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { template struct exe_setter_ @@ -47,7 +47,7 @@ struct char_converter> { static exe_setter_ conv(const exe_setter_ & in) { - return {::boost::process::detail::convert(in.exe_)}; + return {::boost::process::v1::detail::convert(in.exe_)}; } }; @@ -56,7 +56,7 @@ struct char_converter> { static exe_setter_ conv(const exe_setter_ & in) { - return {::boost::process::detail::convert(in.exe_)}; + return {::boost::process::v1::detail::convert(in.exe_)}; } }; @@ -105,7 +105,7 @@ struct char_converter> std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::wstring & ws) { - return ::boost::process::detail::convert(ws); + return ::boost::process::v1::detail::convert(ws); }); return {vec}; } @@ -120,7 +120,7 @@ struct char_converter> std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::string & ws) { - return ::boost::process::detail::convert(ws); + return ::boost::process::v1::detail::convert(ws); }); return {vec}; @@ -136,7 +136,7 @@ struct char_converter> std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::wstring & ws) { - return ::boost::process::detail::convert(ws); + return ::boost::process::v1::detail::convert(ws); }); return {vec}; } }; @@ -150,7 +150,7 @@ struct char_converter> std::transform(in._args.begin(), in._args.end(), vec.begin(), [](const std::string & ws) { - return ::boost::process::detail::convert(ws); + return ::boost::process::v1::detail::convert(ws); }); return {vec}; } @@ -168,7 +168,7 @@ struct exe_builder string_type exe; std::vector args; - void operator()(const boost::process::filesystem::path & data) + void operator()(const boost::process::v1::filesystem::path & data) { not_cmd = true; if (exe.empty()) @@ -285,7 +285,7 @@ struct initializer_builder> typedef exe_builder type; }; -}}} +}}}} diff --git a/include/boost/process/detail/child_decl.hpp b/include/boost/process/v1/detail/child_decl.hpp similarity index 74% rename from include/boost/process/detail/child_decl.hpp rename to include/boost/process/v1/detail/child_decl.hpp index 452295a0c..bb84e93af 100644 --- a/include/boost/process/detail/child_decl.hpp +++ b/include/boost/process/v1/detail/child_decl.hpp @@ -17,7 +17,7 @@ #ifndef BOOST_PROCESS_CHILD_DECL_HPP #define BOOST_PROCESS_CHILD_DECL_HPP -#include +#include #include #include @@ -25,36 +25,36 @@ #include #if defined(BOOST_POSIX_API) -#include -#include -#include -#include +#include +#include +#include +#include #elif defined(BOOST_WINDOWS_API) -#include -#include -#include -#include +#include +#include +#include +#include #endif namespace boost { -namespace process { +namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { -using ::boost::process::detail::api::pid_t; +using ::boost::process::v1::detail::api::pid_t; class child { - ::boost::process::detail::api::child_handle _child_handle; - std::shared_ptr> _exit_status = std::make_shared>(::boost::process::detail::api::still_active); + ::boost::process::v1::detail::api::child_handle _child_handle; + std::shared_ptr> _exit_status = std::make_shared>(::boost::process::v1::detail::api::still_active); bool _attached = true; bool _terminated = false; bool _exited() { - return _terminated || !::boost::process::detail::api::is_running(_exit_status->load()); + return _terminated || !::boost::process::v1::detail::api::is_running(_exit_status->load()); }; public: - typedef ::boost::process::detail::api::child_handle child_handle; + typedef ::boost::process::v1::detail::api::child_handle child_handle; typedef child_handle::process_handle_t native_handle_t; explicit child(child_handle &&ch, std::shared_ptr> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} explicit child(child_handle &&ch, const std::shared_ptr> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} @@ -98,7 +98,7 @@ class child 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());} + int exit_code() const {return ::boost::process::v1::detail::api::eval_exit_status(_exit_status->load());} pid_t id() const {return _child_handle.id(); } int native_exit_code() const {return _exit_status->load();} @@ -107,7 +107,7 @@ class child { std::error_code ec; bool b = running(ec); - boost::process::detail::throw_error(ec, "running error"); + boost::process::v1::detail::throw_error(ec, "running error"); return b; } @@ -115,14 +115,14 @@ class child { std::error_code ec; terminate(ec); - boost::process::detail::throw_error(ec, "terminate error"); + boost::process::v1::detail::throw_error(ec, "terminate error"); } void wait() { std::error_code ec; wait(ec); - boost::process::detail::throw_error(ec, "wait error"); + boost::process::v1::detail::throw_error(ec, "wait error"); } #if !defined(BOOST_PROCESS_NO_DEPRECATED) @@ -133,7 +133,7 @@ class child { std::error_code ec; bool b = wait_for(rel_time, ec); - boost::process::detail::throw_error(ec, "wait_for error"); + boost::process::v1::detail::throw_error(ec, "wait_for error"); return b; } @@ -143,7 +143,7 @@ class child { std::error_code ec; bool b = wait_until(timeout_time, ec); - boost::process::detail::throw_error(ec, "wait_until error"); + boost::process::v1::detail::throw_error(ec, "wait_until error"); return b; } #endif @@ -154,7 +154,7 @@ class child if (valid() && !_exited() && !ec) { int exit_code = 0; - auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec); + auto res = boost::process::v1::detail::api::is_running(_child_handle, exit_code, ec); if (!ec && !res && !_exited()) _exit_status->store(exit_code); @@ -166,7 +166,7 @@ class child void terminate(std::error_code & ec) noexcept { if (valid() && running(ec) && !ec) - boost::process::detail::api::terminate(_child_handle, ec); + boost::process::v1::detail::api::terminate(_child_handle, ec); if (!ec) _terminated = true; @@ -177,7 +177,7 @@ class child if (!_exited() && valid()) { int exit_code = 0; - boost::process::detail::api::wait(_child_handle, exit_code, ec); + boost::process::v1::detail::api::wait(_child_handle, exit_code, ec); if (!ec) _exit_status->store(exit_code); } @@ -198,7 +198,7 @@ class child if (!_exited()) { int exit_code = 0; - auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec); + auto b = boost::process::v1::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec); if (!b || ec) return false; _exit_status->store(exit_code); @@ -225,6 +225,7 @@ class child -}} +}}} + #endif diff --git a/include/boost/process/detail/config.hpp b/include/boost/process/v1/detail/config.hpp similarity index 91% rename from include/boost/process/detail/config.hpp rename to include/boost/process/v1/detail/config.hpp index eec7bde10..60978cc01 100644 --- a/include/boost/process/detail/config.hpp +++ b/include/boost/process/v1/detail/config.hpp @@ -21,8 +21,18 @@ #include #include +#if !defined(BOOST_PROCESS_VERSION) +#define BOOST_PROCESS_VERSION 1 +#endif + +#if BOOST_PROCESS_VERSION == 1 +#define BOOST_PROCESS_V1_INLINE inline +#else +#define BOOST_PROCESS_V1_INLINE +#endif + #include -#include +#include #include #if defined(BOOST_POSIX_API) @@ -38,7 +48,9 @@ extern char **environ; #error "System API not supported by boost.process" #endif -namespace boost { namespace process { namespace detail + + +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { #if !defined(BOOST_PROCESS_PIPE_SIZE) @@ -121,5 +133,7 @@ template<> constexpr wchar_t space_sign () {return L' '; } } } } +} + #endif diff --git a/include/boost/process/detail/execute_impl.hpp b/include/boost/process/v1/detail/execute_impl.hpp similarity index 89% rename from include/boost/process/detail/execute_impl.hpp rename to include/boost/process/v1/detail/execute_impl.hpp index 77722f78c..9f305250d 100644 --- a/include/boost/process/detail/execute_impl.hpp +++ b/include/boost/process/v1/detail/execute_impl.hpp @@ -17,17 +17,17 @@ #ifndef BOOST_PROCESS_EXECUTE_HPP #define BOOST_PROCESS_EXECUTE_HPP -#include -#include +#include +#include #if defined(BOOST_POSIX_API) -#include +#include #elif defined(BOOST_WINDOWS_API) -#include +#include #endif -#include -#include +#include +#include #include #include @@ -40,7 +40,7 @@ #include #include -namespace boost { namespace process { +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { class child; @@ -228,7 +228,7 @@ inline child basic_execute_impl(Args && ... args) boost::fusion::tuple::type&...> tup(args...); auto inits = boost::fusion::filter_if< - boost::process::detail::is_initializer< + boost::process::v1::detail::is_initializer< typename std::remove_reference< boost::mpl::_ >::type @@ -237,7 +237,7 @@ inline child basic_execute_impl(Args && ... args) auto others = boost::fusion::filter_if< boost::mpl::not_< - boost::process::detail::is_initializer< + boost::process::v1::detail::is_initializer< typename std::remove_reference< boost::mpl::_ >::type @@ -250,20 +250,20 @@ inline child basic_execute_impl(Args && ... args) //typedef typename boost::fusion::result_of::as_vector::type inits_t; typedef typename boost::fusion::result_of::as_vector::type others_t; // typedef decltype(others) others_t; - typedef typename ::boost::process::detail::make_builders_from_view< + typedef typename ::boost::process::v1::detail::make_builders_from_view< typename boost::fusion::result_of::begin::type, typename boost::fusion::result_of::end ::type>::type builder_t; builder_t builders; - ::boost::process::detail::builder_ref builder_ref(builders); + ::boost::process::v1::detail::builder_ref builder_ref(builders); boost::fusion::for_each(others, builder_ref); - auto other_inits = ::boost::process::detail::get_initializers(builders); + auto other_inits = ::boost::process::v1::detail::get_initializers(builders); boost::fusion::joint_view complete_inits(other_inits, inits); - auto exec = boost::process::detail::api::make_executor(complete_inits); + auto exec = boost::process::v1::detail::api::make_executor(complete_inits); return exec(); } @@ -273,12 +273,11 @@ inline child execute_impl(Args&& ... args) typedef required_char_type_t req_char_type; return basic_execute_impl( - boost::process::detail::char_converter_t::conv( + boost::process::v1::detail::char_converter_t::conv( std::forward(args))... ); } -}}} - +}}}} #endif diff --git a/include/boost/process/detail/handler.hpp b/include/boost/process/v1/detail/handler.hpp similarity index 83% rename from include/boost/process/detail/handler.hpp rename to include/boost/process/v1/detail/handler.hpp index 1cc5d624b..a12aec543 100644 --- a/include/boost/process/detail/handler.hpp +++ b/include/boost/process/v1/detail/handler.hpp @@ -7,16 +7,16 @@ #ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_ #define BOOST_PROCESS_DETAIL_HANDLER_HPP_ -#include +#include #if defined(BOOST_POSIX_API) -#include +#include #elif defined(BOOST_WINDOWS_API) -#include +#include #endif -namespace boost { namespace process { namespace detail { +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { //extended handler base. typedef api::handler_base_ext handler; @@ -68,8 +68,6 @@ struct on_success_ : handler -}} - - +}}} #endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */ diff --git a/include/boost/process/detail/handler_base.hpp b/include/boost/process/v1/detail/handler_base.hpp similarity index 90% rename from include/boost/process/detail/handler_base.hpp rename to include/boost/process/v1/detail/handler_base.hpp index 93a80520e..732b13c42 100644 --- a/include/boost/process/detail/handler_base.hpp +++ b/include/boost/process/v1/detail/handler_base.hpp @@ -11,9 +11,10 @@ #ifndef BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP #define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP +#include #include -namespace boost { namespace process { namespace detail { +namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { template