mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
118 Commits
variant
...
boost-1.64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4075371cbe | ||
|
|
d5d2c7b2ff | ||
|
|
1ac22670c7 | ||
|
|
477a60ead3 | ||
|
|
04063ee076 | ||
|
|
384e712912 | ||
|
|
64bf929094 | ||
|
|
18ab3ae8c1 | ||
|
|
6c63771ca9 | ||
|
|
3a733827eb | ||
|
|
226b3bd1fc | ||
|
|
158565dbef | ||
|
|
a410059f6b | ||
|
|
3cf5cf49e3 | ||
|
|
deb6af4b2b | ||
|
|
b784a5b3cf | ||
|
|
f74523503d | ||
|
|
41ead2a2d6 | ||
|
|
aa048edd69 | ||
|
|
b15530152a | ||
|
|
3b4bf985f1 | ||
|
|
d218ba7b48 | ||
|
|
94f87c4615 | ||
|
|
99029b9cb7 | ||
|
|
ba5a6bfcf1 | ||
|
|
054bdc47c1 | ||
|
|
6b433c8788 | ||
|
|
cf2a196d40 | ||
|
|
843e56ec1a | ||
|
|
e4a00c9545 | ||
|
|
55b338ab7c | ||
|
|
f18b585740 | ||
|
|
87027b2176 | ||
|
|
e4a3d459c5 | ||
|
|
4d6e802fca | ||
|
|
2f6e83b4e4 | ||
|
|
da42203fef | ||
|
|
87cbedccd8 | ||
|
|
d561667301 | ||
|
|
9cfab7e19c | ||
|
|
4ca67407bb | ||
|
|
70dad97816 | ||
|
|
f14285e954 | ||
|
|
7c108c7540 | ||
|
|
ed8ef66310 | ||
|
|
988515d8d7 | ||
|
|
954ff35e3a | ||
|
|
389dd1adc1 | ||
|
|
167981e273 | ||
|
|
caa7348827 | ||
|
|
c529567a07 | ||
|
|
8729f409f3 | ||
|
|
4f46f43387 | ||
|
|
a69e8d1ebe | ||
|
|
94213f0312 | ||
|
|
22da39b201 | ||
|
|
2a7f5bb66f | ||
|
|
237d5d929f | ||
|
|
6a497ea6a1 | ||
|
|
663fc69691 | ||
|
|
2cb340fb6a | ||
|
|
ed045434a4 | ||
|
|
4ce19ef57e | ||
|
|
6525e639e2 | ||
|
|
f742bf4018 | ||
|
|
7c3640d8c3 | ||
|
|
30ebcfcda6 | ||
|
|
fc601c2e31 | ||
|
|
d1ae99bd1b | ||
|
|
1b0f0cf83e | ||
|
|
5d47a29bfe | ||
|
|
bba7968f7a | ||
|
|
ca1c83cee9 | ||
|
|
5e969baf6b | ||
|
|
684be37ad7 | ||
|
|
17446449a3 | ||
|
|
6f61869867 | ||
|
|
ff1a090026 | ||
|
|
029580c12e | ||
|
|
0d98efe98a | ||
|
|
9db6449044 | ||
|
|
a7d861d806 | ||
|
|
1b737392d0 | ||
|
|
db948e46cb | ||
|
|
56044b1140 | ||
|
|
c0130038e7 | ||
|
|
52ee999d41 | ||
|
|
9c0699ff72 | ||
|
|
c492c099ce | ||
|
|
f2b6cad7ee | ||
|
|
176437d789 | ||
|
|
15c04af3c4 | ||
|
|
ad9d2ce14d | ||
|
|
4f0444a06b | ||
|
|
68b8685d8e | ||
|
|
35ed7fdcc0 | ||
|
|
3edeb104f9 | ||
|
|
e79c9d4322 | ||
|
|
f70f61ccd1 | ||
|
|
6e0754e942 | ||
|
|
9b8f6c4906 | ||
|
|
43fae9108d | ||
|
|
b6a3123f47 | ||
|
|
fb73448cb7 | ||
|
|
8c7d82aa35 | ||
|
|
90f20addd7 | ||
|
|
6c31f3b1a0 | ||
|
|
c4ff1d2bef | ||
|
|
ac28e433a0 | ||
|
|
cceb5bf702 | ||
|
|
46191bc17e | ||
|
|
c893f6e627 | ||
|
|
162c23364d | ||
|
|
13fb61e21a | ||
|
|
0c183fb78f | ||
|
|
e67bd43eb0 | ||
|
|
c832c1443f | ||
|
|
a39fb6d79f |
@@ -26,7 +26,7 @@ env:
|
||||
# By default is eaual to - BOOST_REMOVE=`basename $TRAVIS_BUILD_DIR`
|
||||
# This will force to use local repo content, instead of the Boost's default
|
||||
# not needed because process is not yet in boost.
|
||||
#- BOOST_REMOVE=process
|
||||
- BOOST_REMOVE=process
|
||||
|
||||
matrix:
|
||||
- CXX_STANDARD=c++11 TOOLSET=gcc-5
|
||||
@@ -79,7 +79,8 @@ before_install:
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
# - rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
|
||||
- rm -rf $BOOST/libs/$BOOST_REMOVE
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
@@ -88,8 +89,8 @@ before_install:
|
||||
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 testing.launcher=valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
|
||||
- ../../../b2 address-model=64 architecture=x86 testing.launcher=valgrind valgrind=on toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
- ../../../b2 vfork address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#[Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
|
||||
|
||||
Boost.process is not yet part of the [Boost C++ Libraries](http://github.com/boostorg). It is a library for comfortable management of processes.
|
||||
Boost.process is not yet part of the [Boost C++ Libraries](http://github.com/boostorg), but will probably be released in boost 1.64. It is a library for comfortable management of processes.
|
||||
|
||||
### Test results
|
||||
|
||||
@@ -21,4 +21,4 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
|
||||
|
||||
### Dependency
|
||||
|
||||
This library requires boost 1.63. Since this is not released yet you can clone the winapi module from [here](https://github.com/boostorg/winapi) to get it to work. You will need to overwrite the current code in boost/libs/winapi.
|
||||
This library requires boost 1.63. Since this is not released yet you can clone the winapi module from [here](https://github.com/boostorg/winapi) to get it to work on windows.
|
||||
|
||||
@@ -11,21 +11,54 @@ using boostbook ;
|
||||
using quickbook ;
|
||||
using doxygen ;
|
||||
|
||||
|
||||
local images = [ glob images/*.svg ] ;
|
||||
install images : $(images) : <location>html/boost_process ;
|
||||
install images_glob : $(images) : <location>$(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 ;
|
||||
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
../../../boost/process.hpp
|
||||
[ glob ../../../boost/process/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=YES
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
<doxygen:param>EXAMPLE_PATH=.
|
||||
<dependency>posix_pseudocode
|
||||
<dependency>windows_pseudocode
|
||||
<xsl:path>.
|
||||
;
|
||||
|
||||
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
process.qbk
|
||||
:
|
||||
<dependency>autodoc
|
||||
<dependency>images
|
||||
<dependency>images_glob
|
||||
<xsl:param>boost.root=../../../..
|
||||
<xsl:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: standalone/<format>docbook
|
||||
:
|
||||
: <dependency>images_glob
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
82
doc/concepts.qbk
Normal file
82
doc/concepts.qbk
Normal file
@@ -0,0 +1,82 @@
|
||||
[section:concepts Concepts]
|
||||
In this section, some of the underlying concepts of the operating system used in this library, will be explained.
|
||||
In the following chapters we will presume knowledge of that. Though please note,
|
||||
that this is a short summary and not conclusive of everything that can be done.
|
||||
|
||||
The goal of this library is to implement a portable wrapper, so that we will explain mostly what
|
||||
windows and posix have in common.
|
||||
|
||||
[section:pipes Pipes]
|
||||
Pipes are a facility for communication between different threads, processes and in some cases machines, the operating system provides.
|
||||
|
||||
The typical feature of a pipe is, that it is one channel, to which two handles are given, one for reading (source), one for writing (sink).
|
||||
In that it is different than other facilities (like sockets) and provides another way to manage the connectivity: if one side of the pipe is closed
|
||||
(i.e. the pipe is broken), the other is notified.
|
||||
|
||||
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
|
||||
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
|
||||
|
||||
Though please not, that if the the same thread reads and write to a pipe, it will only talk to itself.
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
The usual type of pipes, are the anonymous ones. Since the have no name,
|
||||
a handle to them can only be obtained from duplicating either handle.
|
||||
|
||||
In this library the following functions are used for the creation of unnamed pipes:
|
||||
|
||||
* [@http://pubs.opengroup.org/onlinepubs/7908799/xsh/pipe.html posix]
|
||||
* [@https://msdn.microsoft.com/de-de/library/windows/desktop/aa365152.aspx windows]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:named Named Pipes]
|
||||
|
||||
As the name suggests, named pipes have a string identifier. This means that a
|
||||
handle to them can be obtained with the identifier, too.
|
||||
|
||||
The implementation on posix uses [@(http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
|
||||
which means, that the named pipe behaves like a file.
|
||||
|
||||
Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes],
|
||||
which also have file-like names, but are in a different scope than the actual file system.
|
||||
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchrounous communication on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:process Processes]
|
||||
|
||||
A process is an independently executable entity, which is different from a thread, in that it has it's own resources.
|
||||
Those include memory and hardware resources.
|
||||
|
||||
Every process is identified by a unique number[footnote it is unique as long as the process is active], called the process identification digit, `pid`.
|
||||
|
||||
[section:exit_code Exit code]
|
||||
A process will return an integer value indicating whether it was successful. On posix
|
||||
there are more codes associated with that, but not so on windows. Therefore there is not such encoding currently in the library.
|
||||
However an exit code of zero means the process was successful, while one different than zero indicates an error.
|
||||
[endsect]
|
||||
|
||||
[section:termination Termination]
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to so and wait, and just terminate the process without conditions.
|
||||
|
||||
Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the
|
||||
library and only the hard terminate is.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:env Environment]
|
||||
|
||||
The environment is a map of variables local to every process. The most significant one for this library
|
||||
is the `PATH` variable, which contains a list of paths, that ought to be searched for executables. A shell will do this automatically,
|
||||
while this library provides a function for that.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -66,7 +66,8 @@ system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
|
||||
|
||||
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
|
||||
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note On windows the path will only be searched for the executable in the command style.]
|
||||
[note The `PATH` variable will automatically be searched in the command style,
|
||||
but the one of the launching process, not the one passed to the child process.]
|
||||
[endsect]
|
||||
|
||||
[section:plat_ext Extensions]
|
||||
|
||||
211
doc/extend.qbk
Normal file
211
doc/extend.qbk
Normal file
@@ -0,0 +1,211 @@
|
||||
[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 io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def __require_io_service__ [classref boost::process::extend::require_io_service ex::require_io_service]]
|
||||
[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]]
|
||||
[def __get_io_service__ [funcref boost::process::extend::get_io_service ex::get_io_service]]
|
||||
|
||||
[section:extend Extensions]
|
||||
To extend the library, the header [headerref boost/process/extend.hpp extend] is provided.
|
||||
|
||||
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 to which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::extend::handler] it will be regarded as a initializer and thus directly put into the sequence
|
||||
the executor gets passed.
|
||||
|
||||
[section:structure Structure]
|
||||
|
||||
The executor calls different handlers of the initializers during the process launch.
|
||||
The basic structure is 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]
|
||||
|
||||
'''
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
'''
|
||||
|
||||
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]
|
||||
|
||||
For more information see the reference of [classref boost::process::extend::posix_executor posix_executor].
|
||||
|
||||
[endsect]
|
||||
[section:simple Simple extensions]
|
||||
|
||||
The simplest extension just takes a single handler, which can be done in a functional style.
|
||||
So let's start with a simple hello-world example, while we use a C++14 generic lambda.
|
||||
|
||||
```
|
||||
using namespace boost::process;
|
||||
namespace ex = bp::extend;
|
||||
|
||||
__child__ c("foo", ex::__on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
|
||||
```
|
||||
|
||||
Considering that lambda 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].
|
||||
|
||||
[note Combined with __on_exit__ this can also handle the process exit.]
|
||||
|
||||
[caution The posix handler symbols are not defined on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[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.
|
||||
So let's implement the hello world example in a class.
|
||||
|
||||
```
|
||||
struct hello_world : __handler__
|
||||
{
|
||||
template<typename Executor>
|
||||
void __on_success__(Executor & exec) const
|
||||
{
|
||||
std::cout << "hello world" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
//in our function
|
||||
__child__ c("foo", hello_world());
|
||||
```
|
||||
|
||||
[note The implementation is done via overloading, not overriding.]
|
||||
|
||||
Every handler not implemented dafaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[section:async Asynchronous Functionality]
|
||||
|
||||
Since `boost.process` provides an interface for [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio],
|
||||
this functionality is also available for extensions. If the class needs the io_service for some reason, the following code will do that.
|
||||
|
||||
```
|
||||
struct async_foo : __handler__, __require_io_service__
|
||||
{
|
||||
tempalte<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
__io_service__ & ios = __get_io_service__(exec.seq); //gives us a reference and a compiler error if not present.
|
||||
//do something with ios
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
[note Inheriting [globalref boost::process::extend::require_io_service require_io_service] is necessary, so [funcref boost::process::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_service require_io_service] .]
|
||||
|
||||
```
|
||||
struct async_bar : __handler, __async_handler__
|
||||
{
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
auto handler = this->handler;
|
||||
return [handler](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
std::cout << "hello world, I exited with " << exit_code << std::endl;
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:error Error handling]
|
||||
|
||||
If an error occurs in the initializers it shall be told to the executor and not handles directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the the executor
|
||||
has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string.
|
||||
Depending on the cofiguration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
|
||||
So let's take a simple example, where we set a randomly chosen `error_code`.
|
||||
|
||||
```
|
||||
auto set_error = [](auto & exec)
|
||||
{
|
||||
std::error_code ec{42, std::system_category()};
|
||||
exec.set_error(ec, "a fake error");
|
||||
|
||||
};
|
||||
__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].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:exec_over Executor Overloading]
|
||||
|
||||
Now that we have a custom initializer, let's consider how we can handle differences between different executors.
|
||||
The distinction is between posix and windows and `char` and `wchar_t` on windows.
|
||||
One solution is to use the [@http://www.boost.org/doc/libs/master/boost/system/api_config.hpp BOOST_WINDOWS_API and BOOST_POSIX_API] macros,
|
||||
which are automatically available as soon as any process-header is included.
|
||||
|
||||
Another variant are the type aliases __posix_executor__ and __windows_executor__, where the executor, not on the current system is a forward-declaration.
|
||||
This works fine, because the function will never get invoked. So let's implement another example, which prints the executable name __on_success__.
|
||||
|
||||
```
|
||||
struct hello_exe : __handler__
|
||||
{
|
||||
template<typename Sequence>
|
||||
void __on_success__(__posix_executor__<Sequence> & exec)
|
||||
{
|
||||
std::cout << "posix-exe: " << exec.exe << std::endl;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
void __on_success__(__windows_executor__<char, Sequence> & exec)
|
||||
{
|
||||
//note: exe might be a nullptr on windows.
|
||||
if (exec.exe != nullptr)
|
||||
std::cout << "windows-exe: " << exec.exe << std::endl;
|
||||
else
|
||||
std::cout << "windows didn't use exe" << std::endl;
|
||||
}
|
||||
|
||||
template<typename Sequence>
|
||||
void __on_success__(__windows_executor__<wchar_t, Sequence> & exec)
|
||||
{
|
||||
//note: exe might be a nullptr on windows.
|
||||
if (exec.exe != nullptr)
|
||||
std::wcout << L"windows-exe: " << exec.exe << std::endl;
|
||||
else
|
||||
std::cout << "windows didn't use exe" << std::endl;
|
||||
}
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
So given our example, the definitions with the non-native exectur are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement systems-specific code without using the preprocessor.
|
||||
|
||||
[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__].
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
44
doc/faq.qbk
44
doc/faq.qbk
@@ -1,10 +1,10 @@
|
||||
[section:faq Frequently Asked Questions]
|
||||
|
||||
|
||||
[section:dead_lock Why does this produce a deadlock?]
|
||||
|
||||
|
||||
Now let's revisit our c++filt example and we will put in an obvious mistake.
|
||||
This might however be not as obvious for more complex applications.
|
||||
|
||||
|
||||
```
|
||||
vector<string> demangle(vector<string> in)
|
||||
{
|
||||
@@ -26,36 +26,36 @@ vector<string> demangle(vector<string> in)
|
||||
We switched the read and write operation up, so that's causing a dead-lock.
|
||||
This locks immediately. This is because `c++filt` expects input, before
|
||||
outputting any data. The launching process on the other hand wait's for it's output.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:closep Why does the pipe not close?]
|
||||
|
||||
|
||||
Now for another example, which might look correct, let's consider you want
|
||||
to use `ls` to read the current directory.
|
||||
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
|
||||
std::string file;
|
||||
while (is >> file)
|
||||
cout << "File: " << file << endl;
|
||||
|
||||
```
|
||||
|
||||
|
||||
This will also deadlock, because the pipe does not close when the subprocess exits.
|
||||
So the `ipstream` will still look for data even though the process has ended.
|
||||
|
||||
|
||||
[note It is not possible to use automatically pipe-closing in this library, because
|
||||
a pipe might be a file-handle (as for async pipes on windows).]
|
||||
|
||||
|
||||
But, since pipes are buffered, you might get incomplete data if you do this:
|
||||
|
||||
|
||||
```
|
||||
ipstream is;
|
||||
child c("ls", std_out > is);
|
||||
|
||||
|
||||
std::string file;
|
||||
while (c.running())
|
||||
{
|
||||
@@ -63,25 +63,25 @@ while (c.running())
|
||||
cout << "File: " << file << endl;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
It is therefore highly recommended that you use the asynchronous api if you are
|
||||
not absolutely sure how the output will look.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:wchar_t When will the codecvt be used?]
|
||||
|
||||
|
||||
Since windows does not use UTF-8 it is sometimes unavoidable to use the `wchar_t` version of the WinApi.
|
||||
To keep this library consistent it provides `wchar_t` support on posix also.
|
||||
|
||||
|
||||
Since the posix api is purely `char` every `wchar_t` based type will be converted into `char`.
|
||||
|
||||
|
||||
Windows on the other hand is more selective; the default is to use `char`,
|
||||
but if any parameter requires `wchar_t`, everything will be converted to `wchar_t`.
|
||||
This also includes `boost::filesystem::path`. Additionally, if the system does not provide
|
||||
the `char` api (as is the case with Windows CE) everything will also be converted.
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
118
doc/images/plantuml.txt
Normal file
118
doc/images/plantuml.txt
Normal file
@@ -0,0 +1,118 @@
|
||||
Plantuml source file (for later edit)
|
||||
// Style
|
||||
|
||||
skinparam backgroundColor #FFFFFF
|
||||
|
||||
skinparam sequence {
|
||||
ActorBorderColor DeepSkyBlue
|
||||
ArrowColor #4a6484
|
||||
|
||||
LifeLineBorderColor #4a6484
|
||||
ParticipantBackgroundColor #91c6ff
|
||||
ParticipantBorderColor black
|
||||
BoxBorderColor black
|
||||
}
|
||||
|
||||
|
||||
//posix no error
|
||||
/**
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
box "Child Process" #LightGrey
|
||||
participant Child
|
||||
participant Exe
|
||||
end box
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : fork
|
||||
activate Child
|
||||
Father -> Father : wait for error
|
||||
deactivate Father
|
||||
|
||||
|
||||
Child->Child : on_exec_setup
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Exe : execve
|
||||
deactivate Child
|
||||
activate Father
|
||||
activate Exe
|
||||
|
||||
Father -> Father : on_success
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
\endplantuml */
|
||||
|
||||
//posix exec error
|
||||
/**
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : fork
|
||||
activate Child
|
||||
Father -> Father : wait for error
|
||||
deactivate Father
|
||||
|
||||
Child->Child : on_exec_setup
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Child : execve
|
||||
Child->Child : on_exec_error
|
||||
activate Child
|
||||
deactivate Child
|
||||
Child->Father : report
|
||||
deactivate Child
|
||||
activate Father
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
\endplantuml
|
||||
|
||||
//posix fork error
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Father : fork
|
||||
Father -> Father : on_fork_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
\endplantuml
|
||||
|
||||
|
||||
//windows.
|
||||
\plantuml
|
||||
activate Father
|
||||
|
||||
Father->Father : on_setup
|
||||
activate Father
|
||||
deactivate Father
|
||||
Father->Child : CreateProcess
|
||||
activate Child
|
||||
|
||||
alt Successful Launch
|
||||
|
||||
Father -> Father : on_success
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
else Error during launch
|
||||
|
||||
Father -> Father : on_error
|
||||
activate Father
|
||||
deactivate Father
|
||||
|
||||
end
|
||||
\endplantuml
|
||||
1
doc/images/posix_exec_err.svg
Normal file
1
doc/images/posix_exec_err.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.9 KiB |
1
doc/images/posix_fork_err.svg
Normal file
1
doc/images/posix_fork_err.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="355px" preserveAspectRatio="none" style="width:142px;height:355px;" version="1.1" viewBox="0 0 142 355" width="142px" zoomAndPan="magnify"><defs><filter height="300%" id="f7wjnsf" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="259.5313" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="34" y="48.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="77.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="191.5625"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="263.6953"/><line style="stroke: #4A6484; stroke-width: 1.0; stroke-dasharray: 5.0,5.0;" x1="39" x2="39" y1="38.2969" y2="316.8281"/><rect fill="#91C6FF" filter="url(#f7wjnsf)" height="30.2969" style="stroke: #000000; stroke-width: 1.5;" width="58" x="8" y="3"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="44" x="15" y="22.9951">Father</text><rect fill="#91C6FF" filter="url(#f7wjnsf)" height="30.2969" style="stroke: #000000; stroke-width: 1.5;" width="58" x="8" y="315.8281"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacingAndGlyphs" textLength="44" x="15" y="335.8232">Father</text><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="259.5313" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="34" y="48.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="77.2969"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="191.5625"/><rect fill="#FFFFFF" filter="url(#f7wjnsf)" height="28" style="stroke: #4A6484; stroke-width: 1.0;" width="10" x="39" y="263.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="69.4297" y2="69.4297"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="69.4297" y2="82.4297"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="82.4297" y2="82.4297"/><polygon fill="#4A6484" points="60,78.4297,50,82.4297,60,86.4297,56,82.4297" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="59" x="56" y="64.3638">on_setup</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="44" x2="86" y1="141.5625" y2="141.5625"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="86" x2="86" y1="141.5625" y2="154.5625"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="45" x2="86" y1="154.5625" y2="154.5625"/><polygon fill="#4A6484" points="55,150.5625,45,154.5625,55,158.5625,51,154.5625" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="24" x="51" y="136.4966">fork</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="183.6953" y2="183.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="183.6953" y2="196.6953"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="196.6953" y2="196.6953"/><polygon fill="#4A6484" points="60,192.6953,50,196.6953,60,200.6953,56,196.6953" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="85" x="56" y="178.6294">on_fork_error</text><line style="stroke: #4A6484; stroke-width: 1.0;" x1="49" x2="91" y1="255.8281" y2="255.8281"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="91" x2="91" y1="255.8281" y2="268.8281"/><line style="stroke: #4A6484; stroke-width: 1.0;" x1="50" x2="91" y1="268.8281" y2="268.8281"/><polygon fill="#4A6484" points="60,264.8281,50,268.8281,60,272.8281,56,268.8281" style="stroke: #4A6484; stroke-width: 1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacingAndGlyphs" textLength="54" x="56" y="250.7622">on_error</text></g></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
1
doc/images/posix_success.svg
Normal file
1
doc/images/posix_success.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 7.7 KiB |
1
doc/images/windows_exec.svg
Normal file
1
doc/images/windows_exec.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.5 KiB |
@@ -13,12 +13,12 @@ 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 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]
|
||||
[intro]
|
||||
|
||||
[caution This is not yet an official Boost C++ library. It wasn't reviewed and can't be downloaded from [@http://www.boost.org/ www.boost.org]. It is however the latest version of an ongoing effort to create a process management library for Boost. For now the library can be downloaded or cloned from here [@https://github.com/klemens-morgenstern/boost-process/tree/develop https://github.com/klemens-morgenstern/boost-process/tree/develop].]
|
||||
|
||||
[endsect]
|
||||
|
||||
60
doc/posix_pseudocode.xml
Normal file
60
doc/posix_pseudocode.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
|
||||
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
|
||||
<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (pid == -1) //fork error
|
||||
{
|
||||
<methodname alt="boost::process::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>()
|
||||
}
|
||||
else if (pid == 0) //child process
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
|
||||
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
|
||||
auto ec = <functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>();
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here the error is send to the father process interally
|
||||
|
||||
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
|
||||
return <classname alt="boost::process::child">child</classname>(); //for C++ compliance
|
||||
}
|
||||
|
||||
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here, we read the the error from the child process
|
||||
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
</programlisting>
|
||||
@@ -12,8 +12,10 @@
|
||||
]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include concepts.qbk]
|
||||
[include tutorial.qbk]
|
||||
[include design.qbk]
|
||||
[include extend.qbk]
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
235
doc/tutorial.qbk
235
doc/tutorial.qbk
@@ -1,20 +1,27 @@
|
||||
[def bp::system [funcref boost::process::system bp::system]]
|
||||
[def bp::spawn [funcref boost::process::system bp::spawn]]
|
||||
[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 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]]
|
||||
@@ -24,22 +31,24 @@
|
||||
[def bp::environment [classref boost::process::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::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::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 __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]]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
In this section we will go step by step through the different features of
|
||||
boost.process. For a full description see the __reference__.
|
||||
boost.process. For a full description see the __reference__ and the __concepts__ sections.
|
||||
|
||||
[section Starting a process]
|
||||
|
||||
@@ -59,55 +68,66 @@ namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
The first thing we can do, is to separate the command and the executable into
|
||||
two parts, so it is more readable and can be built by a function.
|
||||
If a single string (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
That will cause the execution function to search the `PATH` variable to find the executable.
|
||||
The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path),
|
||||
and the rest as arguments passed to said function.
|
||||
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here]]
|
||||
|
||||
So as a first step, we'll use the `exe-args` style.
|
||||
|
||||
```
|
||||
int result = bp::system("g++", "main.cpp");
|
||||
int result = bp::system("/usr/bin/g++", "main.cpp");
|
||||
```
|
||||
|
||||
With that sytax we still have "g++" hard-coded, so let's assume we get the string
|
||||
from an external source as `boost::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = "g++"; //or get it from somewhere else.
|
||||
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
Now, there is a subtle difference between the two syntaxes, i.e. passing a
|
||||
single string or passing multiple. When passing multiple string, the first string will be
|
||||
interpreted as the name of a file and the rest as arguments;
|
||||
when passing one string it will be interpreted as a command.
|
||||
Now we might want to find the `g++` executable in the `PATH`-variable, as the `cmd` syntax would do.
|
||||
`Boost.process` provides a function to this end: bp::search_path.
|
||||
|
||||
For more details please see the [link boost_process.design.arg_cmd_style design description].
|
||||
```
|
||||
boost::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.
|
||||
This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:launch_mode Launch functions]
|
||||
|
||||
Given that in our example used the [funcref boost::process::system system] function,
|
||||
our program will wait until the child process is completed. This is unwanted,
|
||||
our program will wait until the child process is completed. This maybe 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,
|
||||
Besides the already mentioned [funcref boost::process::system system] function and it's
|
||||
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.
|
||||
|
||||
The [funcref boost::process::spawn spawn] function launches a process and
|
||||
immediately detaches so, so no handle will be returned and the process will be ignored.
|
||||
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:
|
||||
|
||||
```
|
||||
bp::spawn("chrome", boost_org);
|
||||
bp::spawn(bp::search_path("chrome"), boost_org);
|
||||
```
|
||||
|
||||
Now for the more sensible approach for compiling, we want a non-blocking execution.
|
||||
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].
|
||||
|
||||
```
|
||||
bp::child c("g++", "main.cpp");
|
||||
bp::child c(bp::search_path("g++"), "main.cpp");
|
||||
|
||||
while (c.child_running())
|
||||
do_some_stuff();
|
||||
@@ -138,7 +158,7 @@ will change the behaviour, so that instead of throwing an exception, the error w
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
bp::system c("g++", "main.cpp", ec);
|
||||
bp::system c("g++ main.cpp", ec);
|
||||
```
|
||||
[endsect]
|
||||
[section:io Synchronous I/O]
|
||||
@@ -148,20 +168,20 @@ The default depends on the system, but usually this will just write it to the sa
|
||||
If this shall be guaranteed, the streams can be explicitly forwarded like this.
|
||||
|
||||
```
|
||||
bp::system("g++", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
|
||||
bp::system("g++ main.cpp", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
|
||||
```
|
||||
|
||||
Now for the first example, we might want to just ignore the output, which can be done by redirecting it to the null-device.
|
||||
This can be achieved this way:
|
||||
|
||||
```
|
||||
bp::system("g++", "main.cpp", bp::std_out > bp::null);
|
||||
bp::system("g++ main.cpp", bp::std_out > bp::null);
|
||||
```
|
||||
|
||||
Alternatively we can also easily redirect the output to a file:
|
||||
|
||||
```
|
||||
bp::system("g++", "main.cpp", bp::std_out > "gcc_out.log");
|
||||
bp::system("g++ main.cpp", bp::std_out > "gcc_out.log");
|
||||
```
|
||||
|
||||
Now, let's take a more visual example for reading data.
|
||||
@@ -180,7 +200,7 @@ wrap around the [classref boost::process::pipe pipe] and provide an implementati
|
||||
std::vector<std::string> read_outline(std::string & file)
|
||||
{
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("nm", file, bp::std_out > is);
|
||||
bp::child c(bp::search_patk("nm"), file, bp::std_out > is);
|
||||
|
||||
std::vector<std::string> data;
|
||||
std::string line;
|
||||
@@ -228,22 +248,20 @@ std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the
|
||||
bp::child nm("nm", file, bp::std_out > p);
|
||||
bp::child filt("c++filt", bp::std_in < p, bp::std_out > is);
|
||||
bp::child nm(bp::search_path("nm"), file, bp::std_out > p);
|
||||
bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is);
|
||||
|
||||
while (nm.running()) //nm finishes automatically, so then we can terminate c++filt.
|
||||
{
|
||||
std::string line;
|
||||
std::getline(is, line);
|
||||
std::string line;
|
||||
while (filt.running() && std::getline(is, line)) //when nm finished the pipe closes and c++filt exits
|
||||
outline.push_back(line);
|
||||
}
|
||||
|
||||
nm.child_wait();
|
||||
filt.child_terminate();
|
||||
filt.wait();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now this forwards the data from `nm` to `c++filt` without your process needing to do anything.
|
||||
This forwards the data from `nm` to `c++filt` without your process needing to do anything.
|
||||
|
||||
[endsect]
|
||||
[section:async_io Asynchronous I/O]
|
||||
@@ -264,7 +282,7 @@ std::vector<char> buf;
|
||||
|
||||
bp::async_pipe ap(ios);
|
||||
|
||||
child c("g++", "main.cpp", bp::std_out > ap);
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > ap);
|
||||
|
||||
asio_async_read(ap, asio_buffer(buf),
|
||||
[](const boost::system::error_code &ec, std::size_t size){});
|
||||
@@ -281,7 +299,7 @@ provided we also pass a reference to an io_service.
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
|
||||
child c("g++", "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
@@ -292,7 +310,7 @@ int result = c.exit_code();
|
||||
[memberref boost::process::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.
|
||||
(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.
|
||||
|
||||
Now we will revisit our first example and read the compiler output asynchronously:
|
||||
|
||||
@@ -310,7 +328,7 @@ child c("g++", "main.cpp", //set the input
|
||||
|
||||
ios.run(); //this will actually block until the compiler is finished
|
||||
|
||||
auto err = fut.get();
|
||||
auto err = data.get();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
@@ -318,18 +336,62 @@ auto err = fut.get();
|
||||
|
||||
When launching several processes, processes can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modifiy the group membership. E.g. if you call `make` which
|
||||
if they do not modify the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
it will not terminate all the child processes of the child unless you use a group.
|
||||
|
||||
The two main reasons to use groups are:
|
||||
|
||||
# Being able two terminate child processes of the child process
|
||||
# Grouping several processes into one, just so they can be terminated at once
|
||||
|
||||
If we have program like `make`, which does launch it's own child processes,
|
||||
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
|
||||
and use the following code, the `gcc` process will still run afterwards:
|
||||
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c1("foo", g);
|
||||
bp::child c2("bar", g);
|
||||
g.group_terminate();
|
||||
bp::child c("make");
|
||||
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
|
||||
c.child_terminate(); //then terminate
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/group.hpp reference] for more information.
|
||||
So in order to also terminate `gcc` we can use a group.
|
||||
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c("make", g);
|
||||
if (!g.group_wait_for(std::chrono::seconds(10))
|
||||
g.group_terminate();
|
||||
|
||||
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].
|
||||
|
||||
|
||||
To put two processes into one group, the following code suffices. Spawn already
|
||||
launches a detached process (i.e. without a child-handle), but they can be grouped,
|
||||
to that in the case of a problem, RAII is still a given.
|
||||
|
||||
```
|
||||
void f()
|
||||
{
|
||||
bp::group g;
|
||||
bp::spawn("foo", g);
|
||||
bp::spawn("bar", g);
|
||||
|
||||
do_something();
|
||||
|
||||
g.group_wait();
|
||||
};
|
||||
```
|
||||
|
||||
In the example, it will wait for both processes at the end of the function unless
|
||||
an exception occures. I.e. if an exception is thrown, the group will be terminated.
|
||||
|
||||
|
||||
Please see the [headerref boost/process/group.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[section:env Environment]
|
||||
@@ -345,87 +407,22 @@ env["VALUE_1"] = "foo";
|
||||
|
||||
//copy it into a environment seperate to the one of this process
|
||||
bp::environment env_ = env;
|
||||
//add a value only to the new env
|
||||
env_["VALUE_2"] = "bar";
|
||||
//append two values to a variable in the new env
|
||||
env_["VALUE_2"] += {"bar1", "bar2"};
|
||||
|
||||
//launch a process with `env_`
|
||||
bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::env env] property.
|
||||
[globalref boost::process::env env] property, which the example as following:
|
||||
|
||||
```
|
||||
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
|
||||
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/environment.hpp reference] for more information.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:coro Coroutines]
|
||||
[section:stackless Stackless Coroutines]
|
||||
|
||||
[note This section presumes knowledge of the boost.asio
|
||||
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/overview/core/coroutine.html stackless coroutine] feature.]
|
||||
|
||||
Stackless coroutines can be implemented rather easily, so there is no need to
|
||||
implement extra functionality concerning boost.process.
|
||||
|
||||
```
|
||||
struct stackless_t : boost::asio::coroutine
|
||||
{
|
||||
bp::child c;
|
||||
|
||||
boost::asio::io_service & ios;
|
||||
|
||||
stackless_t(boost::asio::io_service & ios) : ios(ios) {}
|
||||
|
||||
void operator()(
|
||||
boost::system::error_code ec = boost::system::error_code(),
|
||||
std::size_t n = 0)
|
||||
{
|
||||
if (!ec) reenter (this)
|
||||
{
|
||||
c = bp::child("my_program", ios,
|
||||
bp::on_exit=
|
||||
[this](int, const std::error_code&)
|
||||
{
|
||||
(*this)(); //this is the reentry for the coroutine
|
||||
});
|
||||
yield; //yield the thing.
|
||||
}
|
||||
}
|
||||
};
|
||||
///post the coroutine to a io-service and run it
|
||||
int main()
|
||||
{
|
||||
boost::asio::io_service ios;
|
||||
ios.post(stackless_t(ios));
|
||||
ios.run();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stackful Stackful Coroutines]
|
||||
|
||||
[note This section presumes knowledge of the boost.asio
|
||||
[@http://www.boost.org/doc/libs/release/doc/html/boost_asio/overview/core/spawn.html stackful coroutine] feature.]
|
||||
|
||||
For stackful coroutines this is not as simple, because the members of
|
||||
`boost::asio::yield_context` are not documented. Therefore, boost.process
|
||||
provides a simple way to use stackful coroutines, which looks as follows:
|
||||
|
||||
```
|
||||
void cr(boost::asio::yield_context yield_)
|
||||
{
|
||||
bp::system("my-program", yield_);
|
||||
}
|
||||
```
|
||||
|
||||
This will automatically suspend the coroutine until the child process is finished.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
42
doc/windows_pseudocode.xml
Normal file
42
doc/windows_pseudocode.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
|
||||
exe,
|
||||
cmd_line,
|
||||
proc_attrs,
|
||||
thread_attrs,
|
||||
creation_flags,
|
||||
env,
|
||||
work_dir,
|
||||
startup_info,
|
||||
proc_info);
|
||||
|
||||
<classname alt="boost::process::child">child</classname> c(proc_info, exit_code);
|
||||
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
|
||||
</programlisting>
|
||||
@@ -15,7 +15,7 @@ using namespace boost::process;
|
||||
int main()
|
||||
{
|
||||
ipstream pipe_stream;
|
||||
child c("gcc.exe", "--version", std_out > pipe_stream);
|
||||
child c("gcc --version", std_out > pipe_stream);
|
||||
|
||||
std::string line;
|
||||
|
||||
|
||||
@@ -9,37 +9,38 @@
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace boost::process;
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
//duplicate our pipe descriptor into literal position 4
|
||||
pipe p;
|
||||
system("test", posix::fd.bind(4, p.native_sink()) );
|
||||
bp::pipe p;
|
||||
bp::system("test", bp::posix::fd.bind(4, p.native_sink()));
|
||||
|
||||
|
||||
//close file-descriptor from explicit integral value
|
||||
system("test", posix::fd.close(STDIN_FILENO));
|
||||
bp::system("test", bp::posix::fd.close(STDIN_FILENO));
|
||||
|
||||
//close file-descriptors from explicit integral values
|
||||
system("test", posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
|
||||
bp::system("test", bp::posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
|
||||
|
||||
//add custom handlers
|
||||
const char *env[2] = { 0 };
|
||||
env[0] = "LANG=de";
|
||||
system("test",
|
||||
on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
|
||||
posix::on_fork_error([](auto&)
|
||||
bp::system("test",
|
||||
bp::extend::on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
|
||||
bp::extend::on_fork_error([](auto&, const std::error_code & ec)
|
||||
{ std::cerr << errno << std::endl; }),
|
||||
posix::on_exec_setup([](auto&)
|
||||
bp::extend::on_exec_setup([](auto&)
|
||||
{ ::chroot("/new/root/directory/"); }),
|
||||
posix::on_exec_error([](auto&)
|
||||
bp::extend::on_exec_error([](auto&, const std::error_code & ec)
|
||||
{ std::ofstream ofs("log.txt"); if (ofs) ofs << errno; })
|
||||
);
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <boost/process/args.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/async_system.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/cmd.hpp>
|
||||
|
||||
@@ -101,15 +101,24 @@ on_exit=function;
|
||||
on_exit(function);
|
||||
\endcode
|
||||
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)`.
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
|
||||
`std::future<int>`.
|
||||
|
||||
\par Example
|
||||
|
||||
\code{.cpp}
|
||||
io_service ios;
|
||||
spawn("ls", on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
std::future<int> exit_code;
|
||||
chlid c2("ls", on_exit=exit_code);
|
||||
|
||||
\endcode
|
||||
|
||||
\note The handler is not invoked when the launch fails.
|
||||
\warning When used \ref ignore_error it might gte invoked on error.
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
@@ -160,26 +160,22 @@ public:
|
||||
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
|
||||
|
||||
/** Start an asynchronous read.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
ReadHandler, void(boost::system::error_code, std::size_t))
|
||||
async_read_some(
|
||||
detail::dummy async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler);
|
||||
|
||||
/** Start an asynchronous write.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
|
||||
*/
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
WriteHandler, void(boost::system::error_code, std::size_t))
|
||||
async_write_some(
|
||||
detail::dummy async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler);
|
||||
|
||||
|
||||
142
include/boost/process/async_system.hpp
Normal file
142
include/boost/process/async_system.hpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/async_system.hpp
|
||||
*
|
||||
* Defines the asynchrounous version of the system function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
#define BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/detail/async_handler.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <tuple>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ExitHandler>
|
||||
struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
{
|
||||
boost::asio::io_service & ios;
|
||||
boost::asio::detail::async_result_init<
|
||||
ExitHandler, void(boost::system::error_code, int)> init;
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
bool errored = false;
|
||||
#endif
|
||||
|
||||
template<typename ExitHandler_>
|
||||
async_system_handler(
|
||||
boost::asio::io_service & ios,
|
||||
ExitHandler_ && exit_handler) : ios(ios), init(std::forward<ExitHandler_>(exit_handler))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Exec>
|
||||
void on_error(Exec&, const std::error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
errored = true;
|
||||
#endif
|
||||
auto & h = init.handler;
|
||||
ios.post(
|
||||
[h, ec]() mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
get_result()
|
||||
{
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
if (errored)
|
||||
return [](int exit_code, const std::error_code & ec){};
|
||||
#endif
|
||||
auto & h = init.handler;
|
||||
return [h](int exit_code, const std::error_code & ec) mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ExitHandler>
|
||||
struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
|
||||
|
||||
}
|
||||
|
||||
/** This function provides an asynchronous interface to process launching.
|
||||
|
||||
It uses the same properties and parameters as the other launching function,
|
||||
but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
|
||||
|
||||
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
|
||||
the return value (from the second parameter, `exit_handler`).
|
||||
|
||||
\param ios A reference to an [io_service](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
|
||||
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
|
||||
|
||||
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
|
||||
|
||||
*/
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline boost::process::detail::dummy
|
||||
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args);
|
||||
#endif
|
||||
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
async_system(boost::asio::io_service & ios, ExitHandler && exit_handler, Args && ...args)
|
||||
{
|
||||
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
|
||||
|
||||
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
|
||||
has_err_handling;
|
||||
|
||||
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
|
||||
|
||||
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
|
||||
return async_h.get_result();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
@@ -99,13 +99,16 @@ class child
|
||||
/** \overload void wait() */
|
||||
void wait(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit for a period of time. */
|
||||
/** Wait for the child process to exit for a period of time.
|
||||
* \return True if child exited while waiting.
|
||||
*/
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit until a point in time. */
|
||||
/** Wait for the child process to exit until a point in time.
|
||||
* \return True if child exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
|
||||
|
||||
@@ -7,22 +7,22 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/cmd.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
/** \file boost/process/cmd.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
|
||||
@@ -37,14 +37,14 @@ namespace boost {
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() {}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const Char *s) const
|
||||
{
|
||||
@@ -55,7 +55,7 @@ struct cmd_
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
@@ -67,11 +67,11 @@ struct cmd_
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, api::cmd_setter_<wchar_t>>
|
||||
{
|
||||
@@ -80,7 +80,7 @@ struct char_converter<char, api::cmd_setter_<wchar_t>>
|
||||
return { ::boost::process::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, api::cmd_setter_<char>>
|
||||
{
|
||||
@@ -89,34 +89,34 @@ struct char_converter<wchar_t, api::cmd_setter_<char>>
|
||||
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
|
||||
|
||||
@@ -97,49 +97,14 @@ struct needs_io_service<T>
|
||||
typedef typename does_require_io_service<T>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context
|
||||
{
|
||||
typedef std::false_type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context<::boost::asio::basic_yield_context<T>>
|
||||
{
|
||||
typedef std::true_type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_yield_context;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_yield_context<T, Args...>
|
||||
{
|
||||
typedef typename has_yield_context<Args...>::type next;
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_yield_context<T>
|
||||
{
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...args)
|
||||
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(First & f, Args&...args)
|
||||
boost::asio::io_service &get_io_service_var(First&, Args&...args)
|
||||
{
|
||||
return get_io_service_var(args...);
|
||||
}
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
|
||||
#if defined( BOOST_WINDOWS_API )
|
||||
#include <boost/process/detail/windows/basic_cmd.hpp>
|
||||
#include <boost/process/detail/windows/cmd.hpp>
|
||||
@@ -20,28 +20,28 @@
|
||||
#include <boost/process/detail/posix/basic_cmd.hpp>
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#include <boost/process/shell.hpp>
|
||||
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct exe_setter_
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<Char> string_type;
|
||||
|
||||
|
||||
string_type exe_;
|
||||
exe_setter_(string_type && str) : exe_(std::move(str)) {}
|
||||
exe_setter_(const string_type & str) : exe_(str) {}
|
||||
};
|
||||
|
||||
|
||||
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, exe_setter_<wchar_t>>
|
||||
{
|
||||
@@ -50,7 +50,7 @@ struct char_converter<char, exe_setter_<wchar_t>>
|
||||
return {::boost::process::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, exe_setter_<char>>
|
||||
{
|
||||
@@ -59,27 +59,27 @@ struct char_converter<wchar_t, exe_setter_<char>>
|
||||
return {::boost::process::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename Char, bool Append >
|
||||
struct arg_setter_
|
||||
{
|
||||
using value_type = Char;
|
||||
using string_type = std::basic_string<value_type>;
|
||||
std::vector<string_type> _args;
|
||||
|
||||
|
||||
typedef typename std::vector<string_type>::iterator iterator;
|
||||
typedef typename std::vector<string_type>::const_iterator const_iterator;
|
||||
|
||||
|
||||
template<typename Iterator>
|
||||
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
|
||||
|
||||
|
||||
template<typename Range>
|
||||
arg_setter_(Range && str) :
|
||||
_args(std::begin(str),
|
||||
std::end(str)) {}
|
||||
|
||||
|
||||
iterator begin() {return _args.begin();}
|
||||
iterator end() {return _args.end();}
|
||||
const_iterator begin() const {return _args.begin();}
|
||||
@@ -88,14 +88,14 @@ struct arg_setter_
|
||||
arg_setter_(string_type && s) : _args({std::move(s)}) {}
|
||||
arg_setter_(const string_type & s) : _args({s}) {}
|
||||
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
|
||||
|
||||
|
||||
template<std::size_t Size>
|
||||
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
|
||||
};
|
||||
|
||||
|
||||
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
|
||||
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, arg_setter_<wchar_t, true>>
|
||||
{
|
||||
@@ -110,7 +110,7 @@ struct char_converter<char, arg_setter_<wchar_t, true>>
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, arg_setter_<char, true>>
|
||||
{
|
||||
@@ -122,11 +122,11 @@ struct char_converter<wchar_t, arg_setter_<char, true>>
|
||||
{
|
||||
return ::boost::process::detail::convert(ws);
|
||||
});
|
||||
|
||||
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, arg_setter_<wchar_t, false>>
|
||||
{
|
||||
@@ -140,11 +140,11 @@ struct char_converter<char, arg_setter_<wchar_t, false>>
|
||||
});
|
||||
return {vec}; }
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, arg_setter_<char, false>>
|
||||
{
|
||||
static arg_setter_<wchar_t, false> conv2(const arg_setter_<char, false> & in)
|
||||
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
|
||||
{
|
||||
std::vector<std::wstring> vec(in._args.size());
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
@@ -155,9 +155,9 @@ struct char_converter<wchar_t, arg_setter_<char, false>>
|
||||
return {vec};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using api::exe_cmd_init;
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct exe_builder
|
||||
{
|
||||
@@ -167,7 +167,7 @@ struct exe_builder
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type exe;
|
||||
std::vector<string_type> args;
|
||||
|
||||
|
||||
void operator()(const boost::filesystem::path & data)
|
||||
{
|
||||
not_cmd = true;
|
||||
@@ -176,7 +176,7 @@ struct exe_builder
|
||||
else
|
||||
args.push_back(data.native());
|
||||
}
|
||||
|
||||
|
||||
void operator()(const string_type & data)
|
||||
{
|
||||
if (exe.empty())
|
||||
@@ -196,10 +196,10 @@ struct exe_builder
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
|
||||
auto itr = std::make_move_iterator(data.begin());
|
||||
auto end = std::make_move_iterator(data.end());
|
||||
|
||||
|
||||
if (exe.empty())
|
||||
{
|
||||
exe = *itr;
|
||||
@@ -207,15 +207,15 @@ struct exe_builder
|
||||
}
|
||||
args.insert(args.end(), itr, end);
|
||||
}
|
||||
|
||||
|
||||
void operator()(const std::vector<string_type> & data)
|
||||
{
|
||||
if (data.empty())
|
||||
return;
|
||||
|
||||
|
||||
auto itr = data.begin();
|
||||
auto end = data.end();
|
||||
|
||||
|
||||
if (exe.empty())
|
||||
{
|
||||
exe = *itr;
|
||||
@@ -253,7 +253,7 @@ struct exe_builder
|
||||
{
|
||||
args.insert(args.end(), data._args.begin(), data._args.end());
|
||||
}
|
||||
|
||||
|
||||
api::exe_cmd_init<Char> get_initializer()
|
||||
{
|
||||
if (not_cmd || !args.empty())
|
||||
@@ -268,25 +268,25 @@ struct exe_builder
|
||||
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
|
||||
else
|
||||
return api::exe_cmd_init<Char>::cmd(std::move(exe));
|
||||
|
||||
|
||||
}
|
||||
typedef api::exe_cmd_init<Char> result_type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<char>>
|
||||
{
|
||||
typedef exe_builder<char> type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
|
||||
{
|
||||
typedef exe_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <errno.h>
|
||||
#if defined(__GLIBC__)
|
||||
#include <features.h>
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
#else
|
||||
@@ -74,19 +78,19 @@ inline void throw_last_error()
|
||||
}
|
||||
|
||||
|
||||
template<typename Char> constexpr static Char null_char();
|
||||
template<typename Char> constexpr Char null_char();
|
||||
template<> constexpr char null_char<char> (){return '\0';}
|
||||
template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';}
|
||||
|
||||
template<typename Char> constexpr static Char equal_sign();
|
||||
template<typename Char> constexpr Char equal_sign();
|
||||
template<> constexpr char equal_sign<char> () {return '='; }
|
||||
template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; }
|
||||
|
||||
template<typename Char> constexpr static Char quote_sign();
|
||||
template<typename Char> constexpr Char quote_sign();
|
||||
template<> constexpr char quote_sign<char> () {return '"'; }
|
||||
template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; }
|
||||
|
||||
template<typename Char> constexpr static Char space_sign();
|
||||
template<typename Char> constexpr Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
|
||||
@@ -250,12 +250,12 @@ inline child basic_execute_impl(Args && ... args)
|
||||
//typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t;
|
||||
typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
|
||||
// typedef decltype(others) others_t;
|
||||
typedef typename detail::make_builders_from_view<
|
||||
typedef typename ::boost::process::detail::make_builders_from_view<
|
||||
typename boost::fusion::result_of::begin<others_t>::type,
|
||||
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
|
||||
|
||||
builder_t builders;
|
||||
detail::builder_ref<builder_t> builder_ref(builders);
|
||||
::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
|
||||
|
||||
boost::fusion::for_each(others, builder_ref);
|
||||
auto other_inits = ::boost::process::detail::get_initializers(builders);
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
//extended handler base.
|
||||
typedef api::handler_base_ext handler;
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_setup_ : handler
|
||||
{
|
||||
explicit on_setup_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor &e)
|
||||
{
|
||||
@@ -35,12 +35,12 @@ struct on_setup_ : handler
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_error_ : handler
|
||||
{
|
||||
explicit on_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor &e, const std::error_code &ec)
|
||||
{
|
||||
@@ -49,12 +49,12 @@ struct on_error_ : handler
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_success_ : handler
|
||||
{
|
||||
explicit on_success_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor &e)
|
||||
{
|
||||
@@ -63,16 +63,13 @@ struct on_success_ : handler
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error;
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace boost { namespace process { namespace detail {
|
||||
template<template <class> class Template>
|
||||
struct make_handler_t
|
||||
{
|
||||
constexpr make_handler_t() {}
|
||||
template<typename Handler>
|
||||
constexpr Template<Handler> operator()(Handler handler) const {return Template<Handler>(handler);}
|
||||
template<typename Handler>
|
||||
|
||||
@@ -2,39 +2,39 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct require_io_service {};
|
||||
|
||||
|
||||
struct async_handler : handler_base_ext, require_io_service
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_async_handler : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
|
||||
|
||||
@@ -6,35 +6,35 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
@@ -45,7 +45,7 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise = this->promise;
|
||||
|
||||
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe, promise](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
@@ -61,34 +61,35 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
else
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&ec, std::size_t size){});
|
||||
|
||||
::close(pipe->native_source());
|
||||
|
||||
std::move(*pipe).source().close();
|
||||
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(pipe->native_source());
|
||||
std::move(*pipe).source().close();
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
::close(pipe->native_source());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
|
||||
|
||||
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
@@ -19,67 +19,67 @@
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
{
|
||||
return ::dup2(handle, STDOUT_FILENO);
|
||||
}
|
||||
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
|
||||
{
|
||||
return ::dup2(handle, STDERR_FILENO);
|
||||
}
|
||||
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
return -1;
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
return -1;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
boost::asio::async_read(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&, std::size_t size){});
|
||||
|
||||
|
||||
this->pipe = nullptr;
|
||||
::close(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
@@ -87,24 +87,24 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
::close(pipe->native_sink());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_service
|
||||
{
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
|
||||
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
fut = promise->get_future();
|
||||
@@ -113,12 +113,14 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
inline void on_success(Executor &exec)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
|
||||
auto buffer = this->buffer;
|
||||
auto promise = this->promise;
|
||||
|
||||
boost::asio::async_read(*pipe, *buffer,
|
||||
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
|
||||
{
|
||||
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
|
||||
if (ec && (ec.value() != ENOENT))
|
||||
{
|
||||
std::error_code e(ec.value(), std::system_category());
|
||||
promise->set_exception(std::make_exception_ptr(process_error(e)));
|
||||
@@ -132,37 +134,37 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
promise->set_value(std::move(arg));
|
||||
}
|
||||
});
|
||||
|
||||
::close(pipe->native_sink());
|
||||
|
||||
std::move(*pipe).sink().close();
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
|
||||
|
||||
int res = apply_out_handles(pipe->native_sink(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
::close(pipe->native_sink());
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,8 @@ class async_pipe
|
||||
::boost::asio::posix::stream_descriptor _source;
|
||||
::boost::asio::posix::stream_descriptor _sink ;
|
||||
public:
|
||||
typedef int native_handle;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
|
||||
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
|
||||
|
||||
@@ -124,9 +124,8 @@ public:
|
||||
return _sink.write_some(buffers);
|
||||
}
|
||||
|
||||
native_handle native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
|
||||
native_handle native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
|
||||
|
||||
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
|
||||
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
|
||||
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
@@ -154,19 +153,17 @@ public:
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
const handle_type & source() const & {return _source;}
|
||||
|
||||
handle_type && source()&& { return std::move(_sink); }
|
||||
handle_type && sink() && { return std::move(_source); }
|
||||
handle_type && sink() && { return std::move(_sink); }
|
||||
handle_type && source()&& { return std::move(_source); }
|
||||
|
||||
handle_type source(::boost::asio::io_service& ios) &&
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _source.native_handle());
|
||||
_source.assign(-1);
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
|
||||
return stolen;
|
||||
}
|
||||
handle_type sink (::boost::asio::io_service& ios) &&
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _sink.native_handle());
|
||||
_sink.assign(-1);
|
||||
::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
|
||||
return stolen;
|
||||
}
|
||||
|
||||
@@ -309,7 +306,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
return {source, sink};
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -110,8 +110,11 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
if (exe.empty())
|
||||
if (exe.empty()) //cmd style
|
||||
{
|
||||
exec.exe = args.front().c_str();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
else
|
||||
exec.exe = &exe.front();
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
typedef int native_handle;
|
||||
typedef int native_handle_type;
|
||||
|
||||
basic_pipe()
|
||||
{
|
||||
@@ -71,8 +71,13 @@ public:
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
}
|
||||
native_handle native_source() const {return _source;}
|
||||
native_handle native_sink () const {return _sink;}
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
|
||||
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
|
||||
@@ -22,7 +22,6 @@ namespace posix
|
||||
{
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value)
|
||||
{
|
||||
@@ -61,7 +60,9 @@ struct cmd_setter_ : handler_base_ext
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
exec.exe = _cmd_impl.front();
|
||||
exec.cmd_line = &_cmd_impl.front();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
string_type str() const
|
||||
{
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
@@ -13,10 +13,10 @@
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/locale.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
class native_environment_impl
|
||||
{
|
||||
@@ -51,20 +51,20 @@ public:
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = char_type **;
|
||||
|
||||
|
||||
void reload()
|
||||
{
|
||||
_buffer = _load();
|
||||
_impl = _load_var(_buffer);
|
||||
}
|
||||
|
||||
|
||||
string_type get(const pointer_type id) { return get(string_type(id)); }
|
||||
void set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
set(string_type(id), string_type(value));
|
||||
}
|
||||
void reset(const pointer_type id) { reset(string_type(id)); }
|
||||
|
||||
|
||||
string_type get(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::detail::convert(id);
|
||||
@@ -86,17 +86,17 @@ public:
|
||||
if (res != 0)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = _impl.data();
|
||||
|
||||
|
||||
native_handle_type native_handle() const {return environ;}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
class native_environment_impl<char>
|
||||
{
|
||||
@@ -105,40 +105,41 @@ public:
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = char_type **;
|
||||
|
||||
void reload() {}
|
||||
|
||||
|
||||
void reload() {this->_env_impl = ::environ;}
|
||||
|
||||
string_type get(const pointer_type id) { return getenv(id); }
|
||||
void set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
auto val = std::string(id) + "=" + value;
|
||||
auto res = ::setenv(id, value, true);
|
||||
auto res = ::setenv(id, value, 1);
|
||||
if (res != 0)
|
||||
boost::process::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
void reset(const pointer_type id)
|
||||
{
|
||||
auto res = ::unsetenv(id);
|
||||
if (res != 0)
|
||||
boost::process::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
string_type get(const string_type & id) {return get(id.c_str());}
|
||||
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
|
||||
void reset(const string_type & id) {reset(id.c_str());}
|
||||
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = environ;
|
||||
|
||||
native_handle_type native_handle() const {return environ;}
|
||||
|
||||
native_handle_type native_handle() const {return ::environ;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct basic_environment_impl
|
||||
{
|
||||
@@ -155,21 +156,21 @@ public:
|
||||
_env_arr = _load_var(_data);
|
||||
_env_impl = _env_arr.data();
|
||||
}
|
||||
|
||||
|
||||
string_type get(const pointer_type id) {return get(string_type(id));}
|
||||
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
|
||||
void reset(const pointer_type id) {reset(string_type(id));}
|
||||
|
||||
|
||||
string_type get(const string_type & id);
|
||||
void set(const string_type & id, const string_type & value);
|
||||
void reset(const string_type & id);
|
||||
|
||||
|
||||
basic_environment_impl(const native_environment_impl<Char> & nei);
|
||||
basic_environment_impl() = default;
|
||||
basic_environment_impl(const basic_environment_impl& rhs)
|
||||
: _data(rhs._data)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
basic_environment_impl(basic_environment_impl && ) = default;
|
||||
basic_environment_impl & operator=(const basic_environment_impl& rhs)
|
||||
@@ -180,7 +181,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
basic_environment_impl & operator=(basic_environment_impl && ) = default;
|
||||
|
||||
|
||||
template<typename CharR>
|
||||
explicit inline basic_environment_impl(
|
||||
const basic_environment_impl<CharR>& rhs,
|
||||
@@ -192,11 +193,11 @@ public:
|
||||
{
|
||||
return ::boost::process::detail::convert(st, cv);
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
@@ -205,26 +206,26 @@ public:
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Char ** _env_impl = &*_env_arr.data();
|
||||
|
||||
|
||||
native_handle_type native_handle() const {return &_data.front();}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
|
||||
{
|
||||
auto beg = nei.native_handle();
|
||||
|
||||
|
||||
auto end = beg;
|
||||
while (*end != nullptr)
|
||||
end++;
|
||||
this->_data.assign(beg, end);
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
@@ -236,7 +237,7 @@ inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_t
|
||||
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (itr == _data.end())
|
||||
{
|
||||
return "";
|
||||
@@ -244,7 +245,7 @@ inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_t
|
||||
else return
|
||||
itr->data() + id.size(); //id=Thingy -> +2 points to T
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
|
||||
{
|
||||
@@ -256,19 +257,15 @@ inline void basic_environment_impl<Char>::set(const string_type &id, const strin
|
||||
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
if (itr != _data.end())
|
||||
{
|
||||
*itr = id + equal_sign<Char>() + value;
|
||||
}
|
||||
else
|
||||
{
|
||||
_data.push_back(id + equal_sign<Char>() + value);
|
||||
}
|
||||
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
@@ -286,40 +283,40 @@ inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
}
|
||||
|
||||
reload();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
|
||||
{
|
||||
std::vector<Char*> ret;
|
||||
ret.reserve(data.size() +1);
|
||||
|
||||
|
||||
for (auto & val : data)
|
||||
ret.push_back(&val.front());
|
||||
|
||||
|
||||
ret.push_back(nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
template<typename T> constexpr T env_seperator();
|
||||
template<> constexpr char env_seperator() {return ':'; }
|
||||
template<> constexpr wchar_t env_seperator() {return L':'; }
|
||||
|
||||
|
||||
|
||||
|
||||
typedef int native_handle_t;
|
||||
|
||||
|
||||
inline int get_id() {return getpid(); }
|
||||
inline int native_handle() {return getpid(); }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
#define BOOST_PROCESS_POSIX_EXECUTOR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
@@ -22,9 +22,47 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(__GLIBC__)
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline int execvpe(const char* filename, char * const arg_list[], char* env[])
|
||||
{
|
||||
#if defined(__GLIBC__)
|
||||
return ::execvpe(filename, arg_list, env);
|
||||
#else
|
||||
//use my own implementation
|
||||
std::string fn = filename;
|
||||
if ((fn.find('/') == std::string::npos) && ::access(fn.c_str(), X_OK))
|
||||
{
|
||||
auto e = ::environ;
|
||||
while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if (e != nullptr)
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
boost::split(path, *e, boost::is_any_of(":"));
|
||||
|
||||
for (const std::string & pp : path)
|
||||
{
|
||||
auto p = pp + "/" + filename;
|
||||
if (!::access(p.c_str(), X_OK))
|
||||
{
|
||||
fn = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ::execve(fn.c_str(), arg_list, env);
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_t
|
||||
{
|
||||
@@ -105,6 +143,19 @@ struct on_exec_error_t
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_fork_success_t
|
||||
{
|
||||
Executor & exec;
|
||||
on_fork_success_t(Executor & exec) : exec(exec) {};
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_fork_success(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor> on_setup_t <Executor> call_on_setup (Executor & exec) {return exec;}
|
||||
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
@@ -117,8 +168,9 @@ template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Exe
|
||||
return on_fork_error_t<Executor> (exec, ec);
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
|
||||
template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
|
||||
template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_exec_error_t<Executor> (exec, ec);
|
||||
}
|
||||
@@ -188,7 +240,6 @@ class executor
|
||||
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
|
||||
|
||||
|
||||
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
|
||||
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
|
||||
inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
|
||||
@@ -265,6 +316,7 @@ public:
|
||||
Sequence & seq;
|
||||
const char * exe = nullptr;
|
||||
char *const* cmd_line = nullptr;
|
||||
bool cmd_style = false;
|
||||
char **env = ::environ;
|
||||
pid_t pid = -1;
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
@@ -296,7 +348,10 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
else if (pid == 0)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
if (cmd_style)
|
||||
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
|
||||
else
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
@@ -348,8 +403,10 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
::close(p[0]);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
if (cmd_style)
|
||||
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
|
||||
else
|
||||
::execve(exe, cmd_line, env);
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
@@ -363,12 +420,16 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
|
||||
|
||||
::close(p[1]);
|
||||
_read_error(p[0]);
|
||||
::close(p[0]);
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
else
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
@@ -390,7 +451,6 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
if (_ec)
|
||||
return child();
|
||||
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
@@ -406,7 +466,6 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
@@ -425,6 +484,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
return child();
|
||||
}
|
||||
_ec.clear();
|
||||
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
@@ -439,7 +499,11 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
if (cmd_style)
|
||||
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
|
||||
else
|
||||
::execve(exe, cmd_line, env);
|
||||
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
@@ -447,15 +511,17 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
check_error(has_error_handler());
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
else
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
|
||||
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
enum mode_t
|
||||
@@ -20,38 +20,38 @@ struct file_descriptor
|
||||
write = 2,
|
||||
read_write = 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
file_descriptor() = default;
|
||||
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
|
||||
|
||||
|
||||
explicit file_descriptor(const char* path, mode_t mode = read_write)
|
||||
: _handle(create_file(path, mode))
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
if (_handle != -1)
|
||||
::close(_handle);
|
||||
}
|
||||
|
||||
|
||||
int handle() const { return _handle;}
|
||||
|
||||
|
||||
private:
|
||||
static int create_file(const char* name, mode_t mode )
|
||||
{
|
||||
@@ -67,10 +67,10 @@ private:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int _handle = -1;
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
|
||||
@@ -6,27 +6,27 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct file_in : handler_base_ext
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t)) {}
|
||||
file_in(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_exec_setup(WindowsExecutor &e) const
|
||||
{
|
||||
@@ -34,7 +34,7 @@ struct file_in : handler_base_ext
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,31 +7,31 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : handler_base_ext
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
|
||||
file_out(FILE * f) : handle(fileno(f)) {}
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
@@ -39,7 +39,7 @@ void file_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
@@ -47,19 +47,19 @@ void file_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void file_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,49 +2,48 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
//does not extend anything.
|
||||
struct handler_base_ext : handler_base
|
||||
{
|
||||
template<typename Executor>
|
||||
void on_fork_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_fork_error_ : handler_base_ext
|
||||
{
|
||||
explicit on_fork_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_fork_error(Executor &e) const
|
||||
void on_fork_error(Executor &e, const std::error_code &ec) const
|
||||
{
|
||||
handler_(e);
|
||||
handler_(e, ec);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_exec_setup_ : handler_base_ext
|
||||
{
|
||||
explicit on_exec_setup_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
@@ -53,27 +52,23 @@ struct on_exec_setup_ : handler_base_ext
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
template <class Handler>
|
||||
struct on_exec_error_ : handler_base_ext
|
||||
{
|
||||
explicit on_exec_error_(Handler handler) : handler_(handler) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_error(Executor &e) const
|
||||
void on_exec_error(Executor &e, const std::error_code &ec) const
|
||||
{
|
||||
handler_(e);
|
||||
handler_(e, ec);
|
||||
}
|
||||
private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */
|
||||
|
||||
@@ -2,31 +2,30 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
|
||||
#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/view/transform_view.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <sys/wait.h>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
{
|
||||
@@ -34,77 +33,89 @@ struct on_exit_handler_transformer
|
||||
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
|
||||
template<typename Sig>
|
||||
struct result;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct result<on_exit_handler_transformer<Executor>(T&)>
|
||||
{
|
||||
typedef typename T::on_exit_handler_t type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto operator()(T& t) const -> typename T::on_exit_handler_t
|
||||
{
|
||||
return t.on_exit_handler(exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct async_handler_collector
|
||||
{
|
||||
Executor & exec;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
async_handler_collector(Executor & exec,
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
|
||||
: exec(exec), handlers(handlers) {}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
handlers.push_back(t.on_exit_handler(exec));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//Also set's up waiting for the exit, so it can close async stuff.
|
||||
struct io_service_ref : handler_base_ext
|
||||
{
|
||||
io_service_ref(boost::asio::io_service & ios) : ios(ios)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
boost::asio::io_service &get() {return ios;};
|
||||
|
||||
boost::asio::signal_set *signal_p = nullptr;
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
//must be on the heap so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, exec.exit_status);
|
||||
|
||||
auto signal_p = wh.signal_.get();
|
||||
signal_p->async_wait(std::move(wh));
|
||||
//must be on the heap so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
return;
|
||||
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, exec.exit_status);
|
||||
|
||||
signal_p = wh.signal_.get();
|
||||
signal_p->async_wait(std::move(wh));
|
||||
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor & exec, const std::error_code & ec) const
|
||||
{
|
||||
if (signal_p != nullptr)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
signal_p->cancel(ec);
|
||||
}
|
||||
}
|
||||
|
||||
struct wait_handler
|
||||
{
|
||||
std::shared_ptr<boost::asio::signal_set> signal_;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
std::shared_ptr<std::atomic<int>> exit_status;
|
||||
|
||||
|
||||
wait_handler(const wait_handler & ) = default;
|
||||
wait_handler(wait_handler && ) = default;
|
||||
wait_handler(
|
||||
@@ -114,49 +125,31 @@ struct io_service_ref : handler_base_ext
|
||||
: signal_(new boost::asio::signal_set(ios, SIGCHLD)),
|
||||
funcs(std::move(funcs)),
|
||||
exit_status(exit_status)
|
||||
|
||||
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
void operator()(const boost::system::error_code & ec_in, int /*signal*/)
|
||||
{
|
||||
if (ec_in.value() == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
|
||||
|
||||
int status;
|
||||
::wait(&status);
|
||||
|
||||
|
||||
std::error_code ec(ec_in.value(), std::system_category());
|
||||
int val = WEXITSTATUS(status);
|
||||
exit_status->store(val);
|
||||
|
||||
exit_status->store(status);
|
||||
|
||||
for (auto & func : funcs)
|
||||
func(val, ec);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// Posix specific notifies
|
||||
template <class PosixExecutor>
|
||||
void on_fork_setup(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_prepare);
|
||||
}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_fork_success(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_parent);
|
||||
}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&) const
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_service::fork_child);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service &ios;
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
constexpr static int still_active = 0x7F;
|
||||
constexpr int still_active = 0x7F;
|
||||
static_assert(!WIFEXITED(still_active), "Internal Error");
|
||||
|
||||
inline bool is_running(const child_handle &p, int & exit_code)
|
||||
|
||||
@@ -6,21 +6,21 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct null_in : handler_base_ext
|
||||
{
|
||||
file_descriptor source{"/dev/null", file_descriptor::read};
|
||||
|
||||
|
||||
public:
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
|
||||
|
||||
#include <unistd.h>
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : handler_base_ext
|
||||
{
|
||||
@@ -25,7 +25,7 @@ struct null_out : handler_base_ext
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
@@ -33,7 +33,7 @@ void null_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
@@ -41,18 +41,18 @@ void null_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void null_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
|
||||
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct on_exit_ : boost::process::detail::posix::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
return handler;
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
|
||||
|
||||
@@ -6,46 +6,85 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct pipe_in : handler_base_ext
|
||||
{
|
||||
int descr_;
|
||||
|
||||
int source;
|
||||
int sink; //opposite end
|
||||
|
||||
pipe_in(int sink, int source) : source(source), sink(sink) {}
|
||||
|
||||
|
||||
template<typename T>
|
||||
pipe_in(const T & p) : descr_(p.native_source()) {}
|
||||
|
||||
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
|
||||
{
|
||||
p.assign_source(-1);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(descr_);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(descr_);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDIN_FILENO) == -1)
|
||||
if (::dup2(source, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
::close(source);
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
class async_pipe;
|
||||
|
||||
struct async_pipe_in : public pipe_in
|
||||
{
|
||||
async_pipe &pipe;
|
||||
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).source().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,70 +7,110 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : handler_base_ext
|
||||
{
|
||||
int descr_;
|
||||
|
||||
int sink;
|
||||
int source; //opposite end
|
||||
|
||||
pipe_out(int sink, int source) : sink(sink), source(source) {}
|
||||
|
||||
template<typename T>
|
||||
pipe_out(const T & p) : descr_(p.native_sink()) {}
|
||||
|
||||
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
|
||||
{
|
||||
p.assign_sink(-1);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::close(descr_);
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &) const
|
||||
{
|
||||
::close(descr_);
|
||||
::close(sink);
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
void on_exec_setup(Executor &e) const;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDOUT_FILENO) == -1)
|
||||
if (::dup2(sink, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
|
||||
::close(descr_);
|
||||
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDERR_FILENO) == -1)
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename Executor>
|
||||
void pipe_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(descr_, STDOUT_FILENO) == -1)
|
||||
if (::dup2(sink, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
if (::dup2(descr_, STDERR_FILENO) == -1)
|
||||
if (::dup2(sink, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
::close(descr_);
|
||||
::close(sink);
|
||||
::close(source);
|
||||
}
|
||||
|
||||
|
||||
class async_pipe;
|
||||
|
||||
template<int p1, int p2>
|
||||
struct async_pipe_out : public pipe_out<p1, p2>
|
||||
{
|
||||
async_pipe &pipe;
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).sink().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,9 +16,17 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
#if defined(__GLIBC__)
|
||||
using sighandler_t = ::sighandler_t;
|
||||
#else
|
||||
using sighandler_t = void(*)(int);
|
||||
#endif
|
||||
|
||||
|
||||
struct sig_init_ : handler_base_ext
|
||||
{
|
||||
sig_init_ (::sighandler_t handler) : _handler(handler) {}
|
||||
|
||||
sig_init_ (sighandler_t handler) : _handler(handler) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&)
|
||||
@@ -47,16 +55,16 @@ struct sig_init_ : handler_base_ext
|
||||
}
|
||||
private:
|
||||
bool _reset = false;
|
||||
::sighandler_t _old{0};
|
||||
::sighandler_t _handler{0};
|
||||
::boost::process::detail::posix::sighandler_t _old{0};
|
||||
::boost::process::detail::posix::sighandler_t _handler{0};
|
||||
};
|
||||
|
||||
struct sig_
|
||||
{
|
||||
constexpr sig_() {}
|
||||
|
||||
sig_init_ operator()(::sighandler_t h) const {return h;}
|
||||
sig_init_ operator= (::sighandler_t h) const {return h;}
|
||||
sig_init_ operator()(::boost::process::detail::posix::sighandler_t h) const {return h;}
|
||||
sig_init_ operator= (::boost::process::detail::posix::sighandler_t h) const {return h;}
|
||||
sig_init_ dfl() const {return SIG_DFL;}
|
||||
sig_init_ ign() const {return SIG_IGN;}
|
||||
|
||||
|
||||
@@ -1,157 +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_DETAIL_POSIX_VARIANT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_VARIANT_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/variant/variant.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_error_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code &ec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_error(exec, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_success_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_success(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_fork_error_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code &ec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_fork_error(exec, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exec_setup_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_exec_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exec_error_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code &ec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_exec_error(exec, ec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
struct handler_variant : handler_base_ext, boost::variant<Args...>
|
||||
{
|
||||
using boost::variant<Args...>::variant;
|
||||
using boost::variant<Args...>::operator=;
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
on_setup_visitor<Executor> vis{exec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor& exec, const std::error_code & ec)
|
||||
{
|
||||
on_error_visitor<Executor> vis{exec, ec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec)
|
||||
{
|
||||
on_success_visitor<Executor> vis{exec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_fork_error (Executor & exec, const std::error_code& ec)
|
||||
{
|
||||
on_fork_error_visitor<Executor> vis{exec, ec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor & exec)
|
||||
{
|
||||
on_exec_setup_visitor<Executor> vis{exec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_exec_error (Executor & exec, const std::error_code& ec)
|
||||
{
|
||||
on_exec_error_visitor<Executor> vis{exec, ec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -141,8 +141,6 @@ inline bool wait_until(
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
@@ -177,8 +175,6 @@ inline bool wait_until(
|
||||
pid_t ret;
|
||||
int status;
|
||||
|
||||
auto start = std::chrono::system_clock::now();
|
||||
|
||||
bool time_out_occured = false;
|
||||
do
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace boost { namespace process { namespace detail {
|
||||
struct throw_on_error_ : ::boost::process::detail::handler
|
||||
{
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
void on_error(Executor& exec, const std::error_code & ec) const
|
||||
{
|
||||
throw process_error(ec, "process creation failed");
|
||||
}
|
||||
@@ -29,7 +29,7 @@ struct throw_on_error_ : ::boost::process::detail::handler
|
||||
|
||||
}
|
||||
|
||||
constexpr static boost::process::detail::throw_on_error_ throw_on_error;
|
||||
constexpr boost::process::detail::throw_on_error_ throw_on_error;
|
||||
|
||||
}}
|
||||
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_TRAITS_HPP_
|
||||
#define BOOST_PROCESS_TRAITS_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
#include <boost/process/detail/traits/async.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/env.hpp>
|
||||
#include <boost/process/detail/traits/error.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
|
||||
|
||||
@@ -2,33 +2,33 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
|
||||
class io_service;
|
||||
}}
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
struct async_tag {};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>;
|
||||
|
||||
|
||||
template<> struct initializer_tag<::boost::asio::io_service> { typedef async_tag type;};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
@@ -14,69 +14,72 @@
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct cmd_or_exe_tag {};
|
||||
|
||||
|
||||
struct shell_;
|
||||
|
||||
|
||||
|
||||
|
||||
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
|
||||
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
|
||||
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
|
||||
|
||||
template<> struct initializer_tag<shell_>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
|
||||
template<> struct initializer_tag<boost::filesystem::path>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
|
||||
template <typename Char>
|
||||
struct exe_setter_;
|
||||
template <typename Char, bool Append = false>
|
||||
struct arg_setter_;
|
||||
|
||||
|
||||
template <typename Char, bool Append>
|
||||
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
|
||||
|
||||
|
||||
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<char>>;
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
|
||||
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */
|
||||
|
||||
@@ -2,63 +2,63 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/none.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_initializer : std::is_base_of<handler_base, T> {};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct initializer_tag;// { typedef void type; };
|
||||
|
||||
|
||||
|
||||
|
||||
//remove const
|
||||
template<typename T>
|
||||
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
|
||||
//remove &
|
||||
template<typename T>
|
||||
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
|
||||
//remove const &
|
||||
template<typename T>
|
||||
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct initializer_builder;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
struct valid_argument_list;
|
||||
|
||||
|
||||
template<typename First>
|
||||
struct valid_argument_list<First>
|
||||
{
|
||||
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
struct valid_argument_list
|
||||
{
|
||||
@@ -66,15 +66,11 @@ struct valid_argument_list
|
||||
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
|
||||
typedef std::integral_constant<bool, value> type;
|
||||
};
|
||||
|
||||
struct error_tag;
|
||||
|
||||
template<>
|
||||
struct initializer_tag<std::error_code>;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
|
||||
@@ -2,52 +2,52 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
|
||||
|
||||
|
||||
|
||||
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
class basic_environment;
|
||||
|
||||
|
||||
template<typename Char>
|
||||
class basic_native_environment;
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_tag {};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char> struct env_set;
|
||||
template<typename Char> struct env_append;
|
||||
|
||||
|
||||
template<typename Char> struct env_reset;
|
||||
template<typename Char> struct env_init;
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
|
||||
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
|
||||
|
||||
|
||||
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
|
||||
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
|
||||
|
||||
|
||||
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
|
||||
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
|
||||
|
||||
|
||||
template<> struct initializer_builder<env_tag<char>>;
|
||||
template<> struct initializer_builder<env_tag<wchar_t>>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
|
||||
|
||||
@@ -2,32 +2,26 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct error_tag {};
|
||||
|
||||
|
||||
struct error_tag;
|
||||
|
||||
template<>
|
||||
struct make_initializer_t<error_tag>;
|
||||
|
||||
|
||||
template<> struct initializer_tag_t<std::error_code> { typedef error_tag type;};
|
||||
|
||||
|
||||
|
||||
|
||||
struct initializer_tag<std::error_code>;
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
|
||||
@@ -24,7 +24,7 @@ template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename bo
|
||||
|
||||
template<> struct is_wchar_t<const wchar_t* > : std::true_type {};
|
||||
|
||||
template<> struct is_wchar_t<wchar_t* > { typedef std::true_type type;};
|
||||
template<> struct is_wchar_t<wchar_t* > : std::true_type {};
|
||||
|
||||
template<std::size_t Size> struct is_wchar_t<const wchar_t [Size]> : std::true_type {};
|
||||
template<std::size_t Size> struct is_wchar_t<const wchar_t (&)[Size]> : std::true_type {};
|
||||
@@ -180,7 +180,7 @@ struct char_converter<wchar_t, std::vector<char* >>
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const char* st)
|
||||
{
|
||||
std::size_t sz;
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != '\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
@@ -197,7 +197,7 @@ struct char_converter<wchar_t, std::initializer_list<char *>>
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const char* st)
|
||||
{
|
||||
std::size_t sz;
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != '\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
@@ -244,7 +244,7 @@ struct char_converter<char, std::vector<wchar_t* >>
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const wchar_t* st)
|
||||
{
|
||||
std::size_t sz;
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != L'\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
@@ -261,7 +261,7 @@ struct char_converter<char, std::initializer_list<wchar_t * >>
|
||||
std::transform(in.begin(), in.end(), ret.begin(),
|
||||
[](const wchar_t* st)
|
||||
{
|
||||
std::size_t sz;
|
||||
std::size_t sz = 0;
|
||||
while (st[sz] != L'\0') sz++;
|
||||
return convert(st, st + sz);
|
||||
});
|
||||
|
||||
@@ -2,39 +2,39 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct require_io_service {};
|
||||
|
||||
|
||||
struct async_handler : handler_base_ext, require_io_service
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_async_handler : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
|
||||
template<typename T>
|
||||
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
|
||||
|
||||
@@ -6,15 +6,15 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
|
||||
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
@@ -22,38 +22,38 @@
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
|
||||
std::shared_ptr<std::promise<void>> promise;
|
||||
async_in_buffer operator>(std::future<void> & fut)
|
||||
{
|
||||
promise = std::make_shared<std::promise<void>>();
|
||||
fut = promise->get_future(); return std::move(*this);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
|
||||
|
||||
if (this->promise)
|
||||
{
|
||||
auto promise = this->promise;
|
||||
|
||||
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[promise](const boost::system::error_code & ec, std::size_t)
|
||||
{
|
||||
@@ -67,39 +67,39 @@ struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
}
|
||||
else
|
||||
boost::asio::async_write(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&ec, std::size_t size){});
|
||||
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_source());
|
||||
|
||||
|
||||
[pipe](const boost::system::error_code&, std::size_t){});
|
||||
|
||||
std::move(*pipe).source().close();
|
||||
|
||||
|
||||
this->pipe = nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_source());
|
||||
}
|
||||
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
|
||||
|
||||
::boost::detail::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
|
||||
|
||||
|
||||
boost::detail::winapi::SetHandleInformation(source_handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
exec.startup_info.hStdInput = source_handle;
|
||||
exec.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
exec.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
@@ -17,83 +17,83 @@
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
|
||||
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template <typename Executor>
|
||||
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
|
||||
|
||||
|
||||
|
||||
async_out_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
boost::asio::async_read(*pipe, buf,
|
||||
[pipe](const boost::system::error_code&, std::size_t size){});
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
[pipe](const boost::system::error_code&, std::size_t){});
|
||||
std::move(*pipe).sink().close();
|
||||
this->pipe = nullptr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
@@ -103,9 +103,9 @@ struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
|
||||
::boost::process::detail::windows::require_io_service
|
||||
@@ -113,21 +113,21 @@ struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
|
||||
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
fut = promise->get_future();
|
||||
}
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
inline void on_success(Executor&)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
auto buffer = this->buffer;
|
||||
auto promise = this->promise;
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
boost::asio::async_read(*pipe, *buffer,
|
||||
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
|
||||
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
|
||||
{
|
||||
@@ -140,37 +140,37 @@ struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
|
||||
Type arg;
|
||||
arg.resize(buffer->size());
|
||||
is.read(&*arg.begin(), buffer->size());
|
||||
|
||||
|
||||
promise->set_value(std::move(arg));
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
this->pipe = nullptr;
|
||||
this->buffer = nullptr;
|
||||
this->promise = nullptr;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(pipe->native_sink());
|
||||
std::move(*pipe).sink().close();
|
||||
}
|
||||
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_service(exec.seq));
|
||||
|
||||
|
||||
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -100,20 +100,26 @@ public:
|
||||
if (_sink.is_open())
|
||||
{
|
||||
_sink.close();
|
||||
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
_sink = handle_type(_sink.get_io_service());
|
||||
}
|
||||
if (_source.is_open())
|
||||
{
|
||||
_source.close();
|
||||
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
_source = handle_type(_source.get_io_service());
|
||||
}
|
||||
}
|
||||
void close(boost::system::error_code & ec)
|
||||
{
|
||||
if (_sink.is_open())
|
||||
{
|
||||
_sink.close(ec);
|
||||
_sink = handle_type(_sink.get_io_service());
|
||||
}
|
||||
if (_source.is_open())
|
||||
{
|
||||
_source.close(ec);
|
||||
_source = handle_type(_source.get_io_service());
|
||||
}
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
@@ -345,23 +351,23 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native();
|
||||
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native();
|
||||
|
||||
if (source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, source_in, proc, &source, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if (!::boost::detail::winapi::DuplicateHandle(
|
||||
proc, sink_in, proc, &sink, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
throw_last_error("Duplicate Pipe Failed");
|
||||
|
||||
return {source, sink};
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
}
|
||||
|
||||
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)
|
||||
|
||||
@@ -2,21 +2,21 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
|
||||
|
||||
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iterator>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
@@ -25,28 +25,28 @@ namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
|
||||
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
|
||||
{
|
||||
std::string st = exe;
|
||||
|
||||
|
||||
//put in quotes if it has spaces
|
||||
{
|
||||
boost::replace_all(st, "\"", "\\\"");
|
||||
|
||||
|
||||
auto it = std::find(st.begin(), st.end(), ' ');
|
||||
|
||||
|
||||
if (it != st.end())//contains spaces.
|
||||
{
|
||||
st.insert(st.begin(), '"');
|
||||
st += '"';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, "\"", "\\\"");
|
||||
|
||||
|
||||
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
|
||||
if (it != arg.end())//ok, contains spaces.
|
||||
{
|
||||
@@ -55,22 +55,22 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
|
||||
arg.insert(arg.begin(), '"');
|
||||
arg += '"'; //thats the post one.
|
||||
}
|
||||
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += ' ';
|
||||
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
|
||||
{
|
||||
std::wstring st = exe;
|
||||
for (auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, L"\"", L"\\\"");
|
||||
|
||||
|
||||
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
|
||||
if (it != arg.end())//ok, contains spaces.
|
||||
{
|
||||
@@ -79,35 +79,35 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
|
||||
arg.insert(arg.begin(), L'"');
|
||||
arg += L'"'; //thats the post one.
|
||||
}
|
||||
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += L' ';
|
||||
|
||||
|
||||
st += arg;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct exe_cmd_init : handler_base_ext
|
||||
{
|
||||
using value_type = Char;
|
||||
using string_type = std::basic_string<value_type>;
|
||||
|
||||
|
||||
static const char* c_arg(char) { return "/c";}
|
||||
static const wchar_t* c_arg(wchar_t) { return L"/c";}
|
||||
|
||||
|
||||
exe_cmd_init(const string_type & exe, bool cmd_only = false)
|
||||
: exe(exe), args({}), cmd_only(cmd_only) {};
|
||||
exe_cmd_init(string_type && exe, bool cmd_only = false)
|
||||
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
|
||||
|
||||
|
||||
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
|
||||
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
|
||||
|
||||
if (cmd_only && args.empty())
|
||||
exec.cmd_line = exe.c_str();
|
||||
else
|
||||
@@ -129,18 +129,18 @@ struct exe_cmd_init : handler_base_ext
|
||||
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
|
||||
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
|
||||
string_type sh = get_shell(Char());
|
||||
|
||||
|
||||
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
|
||||
}
|
||||
|
||||
|
||||
static std:: string get_shell(char) {return shell(). string(codecvt()); }
|
||||
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
|
||||
|
||||
|
||||
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
|
||||
{
|
||||
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
|
||||
string_type sh = get_shell(Char());
|
||||
|
||||
|
||||
return exe_cmd_init<Char>(
|
||||
std::move(sh),
|
||||
std::move(args));
|
||||
@@ -150,15 +150,15 @@ private:
|
||||
string_type args;
|
||||
bool cmd_only;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
|
||||
@@ -55,6 +55,9 @@ public:
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
basic_pipe()
|
||||
{
|
||||
if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
|
||||
|
||||
@@ -32,7 +32,7 @@ struct child_handle
|
||||
{
|
||||
auto h = ::boost::detail::winapi::OpenProcess(
|
||||
::boost::detail::winapi::PROCESS_ALL_ACCESS_,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(1),
|
||||
static_cast<::boost::detail::winapi::BOOL_>(0),
|
||||
pid);
|
||||
|
||||
if (h == nullptr)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
@@ -17,13 +17,13 @@ namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
|
||||
template<typename CharType>
|
||||
struct cmd_setter_ : ::boost::process::detail::handler_base
|
||||
{
|
||||
typedef CharType value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
|
||||
|
||||
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
|
||||
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
|
||||
template <class Executor>
|
||||
@@ -32,18 +32,18 @@ struct cmd_setter_ : ::boost::process::detail::handler_base
|
||||
exec.cmd_line = _cmd_line.c_str();
|
||||
}
|
||||
const string_type & str() const {return _cmd_line;}
|
||||
|
||||
|
||||
private:
|
||||
string_type _cmd_line;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
|
||||
@@ -21,8 +21,8 @@ inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::w
|
||||
if (lhs == rhs)
|
||||
return true;
|
||||
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,0,0,0,0,0,0,0,0,0};
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,0,0,0,0,0,0,0,0,0};
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
|
||||
::boost::detail::winapi::BY_HANDLE_FILE_INFORMATION_ rhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
|
||||
|
||||
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
|
||||
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
|
||||
|
||||
#include <boost/detail/winapi/error_codes.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
@@ -24,6 +25,11 @@ struct env_init : public ::boost::process::detail::handler_base
|
||||
env_init(boost::process::basic_environment<Char> && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::basic_environment<Char> & env) : env(env) {};
|
||||
|
||||
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(char) {return 0u;}
|
||||
constexpr static ::boost::detail::winapi::DWORD_ creation_flag(wchar_t)
|
||||
{
|
||||
return ::boost::detail::winapi::CREATE_UNICODE_ENVIRONMENT_;
|
||||
}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &exec) const
|
||||
@@ -32,10 +38,11 @@ struct env_init : public ::boost::process::detail::handler_base
|
||||
if (*e == null_char<char>())
|
||||
{
|
||||
exec.set_error(std::error_code(::boost::detail::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
|
||||
"Bad Environment");
|
||||
"Empty Environment");
|
||||
}
|
||||
|
||||
exec.env = e;
|
||||
exec.creation_flags |= creation_flag(Char());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
@@ -16,9 +16,9 @@
|
||||
#include <boost/detail/winapi/get_current_process_id.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/process/locale.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
class native_environment_impl
|
||||
{
|
||||
@@ -37,25 +37,25 @@ public:
|
||||
_env_arr = _load_var(_buf.get());
|
||||
_env_impl = &*_env_arr.begin();
|
||||
}
|
||||
|
||||
|
||||
string_type get(const pointer_type id);
|
||||
void set(const pointer_type id, const pointer_type value);
|
||||
void reset(const pointer_type id);
|
||||
|
||||
|
||||
string_type get(const string_type & id) {return get(id.c_str());}
|
||||
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
|
||||
void reset(const string_type & id) {reset(id.c_str());}
|
||||
|
||||
|
||||
native_environment_impl() = default;
|
||||
native_environment_impl(const native_environment_impl& ) = delete;
|
||||
native_environment_impl(native_environment_impl && ) = default;
|
||||
native_environment_impl & operator=(const native_environment_impl& ) = delete;
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
Char ** _env_impl = &*_env_arr.begin();
|
||||
|
||||
|
||||
native_handle_type native_handle() const {return _buf.get();}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
|
||||
{
|
||||
@@ -67,10 +67,10 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
if (err == ::boost::detail::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
|
||||
return "";
|
||||
else
|
||||
throw process_error("GetEnvironmentVariable() failed",
|
||||
std::error_code(err, std::system_category()));
|
||||
throw process_error(std::error_code(err, std::system_category()),
|
||||
"GetEnvironmentVariable() failed");
|
||||
}
|
||||
|
||||
|
||||
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
|
||||
{
|
||||
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
|
||||
@@ -83,7 +83,7 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
{
|
||||
std::vector<Char> buf(buf_size);
|
||||
auto size = boost::detail::winapi::get_environment_variable(id, buf.data(), buf.size());
|
||||
|
||||
|
||||
if (size == buf_size) //buffer to small
|
||||
buf_size *= 2;
|
||||
else if (size == 0)
|
||||
@@ -91,25 +91,25 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
else
|
||||
return std::basic_string<Char>(
|
||||
buf.data(), buf.data()+ size + 1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return std::basic_string<Char>(buf, buf+size+1);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
|
||||
{
|
||||
boost::detail::winapi::set_environment_variable(id, value);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void native_environment_impl<Char>::reset(const pointer_type id)
|
||||
{
|
||||
boost::detail::winapi::set_environment_variable(id, nullptr);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
|
||||
{
|
||||
@@ -130,11 +130,11 @@ std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
|
||||
}
|
||||
p++;
|
||||
ret.push_back(nullptr);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct basic_environment_impl
|
||||
{
|
||||
@@ -146,23 +146,23 @@ public:
|
||||
using pointer_type = const char_type*;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using native_handle_type = pointer_type;
|
||||
|
||||
|
||||
std::size_t size() const { return _data.size();}
|
||||
|
||||
|
||||
void reload()
|
||||
{
|
||||
_env_arr = _load_var(_data.data());
|
||||
_env_impl = _env_arr.data();
|
||||
}
|
||||
|
||||
|
||||
string_type get(const pointer_type id) {return get(string_type(id));}
|
||||
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
|
||||
void reset(const pointer_type id) {reset(string_type(id));}
|
||||
|
||||
|
||||
string_type get(const string_type & id);
|
||||
void set(const string_type & id, const string_type & value);
|
||||
void reset(const string_type & id);
|
||||
|
||||
|
||||
inline basic_environment_impl(const native_environment_impl<Char> & nei);
|
||||
basic_environment_impl() = default;
|
||||
basic_environment_impl(const basic_environment_impl& rhs)
|
||||
@@ -181,7 +181,7 @@ public:
|
||||
//reload();
|
||||
_env_arr = std::move(rhs._env_arr);
|
||||
_env_impl = _env_arr.data();
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
basic_environment_impl & operator=(const basic_environment_impl& rhs)
|
||||
@@ -190,7 +190,7 @@ public:
|
||||
reload();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
template<typename CharR>
|
||||
explicit inline basic_environment_impl(
|
||||
const basic_environment_impl<CharR>& rhs,
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
: _data(::boost::process::detail::convert(rhs._data, cv))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
@@ -207,13 +207,13 @@ public:
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Char ** _env_impl = &*_env_arr.begin();
|
||||
|
||||
|
||||
native_handle_type native_handle() const {return &*_data.begin();}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
|
||||
{
|
||||
@@ -223,94 +223,94 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
|
||||
p++;
|
||||
p++; //pointing to the second nullchar
|
||||
p++; //to get the pointer behing the second nullchar, so it's end.
|
||||
|
||||
|
||||
this->_data.assign(beg, p);
|
||||
this->reload();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
|
||||
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
return string_type(_data.data()); //null-char is handled by the string.
|
||||
|
||||
|
||||
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
|
||||
seq.insert(seq.end(), id.begin(), id.end());
|
||||
seq.push_back('=');
|
||||
|
||||
|
||||
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
|
||||
|
||||
|
||||
if (itr == _data.end()) //not found
|
||||
return "";
|
||||
|
||||
|
||||
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
|
||||
|
||||
|
||||
return string_type(&*itr);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
|
||||
{
|
||||
reset(id);
|
||||
|
||||
|
||||
std::vector<Char> insertion;
|
||||
|
||||
|
||||
insertion.insert(insertion.end(), id.begin(), id.end());
|
||||
insertion.push_back('=');
|
||||
insertion.insert(insertion.end(), value.begin(), value.end());
|
||||
insertion.push_back('\0');
|
||||
|
||||
|
||||
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
|
||||
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
//ok, we need to check the size of data first
|
||||
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
|
||||
return;
|
||||
|
||||
|
||||
//check if it's the first one, spares us the search.
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
{
|
||||
auto beg = _data.begin();
|
||||
auto end = beg;
|
||||
|
||||
|
||||
while (*end != '\0')
|
||||
end++;
|
||||
|
||||
|
||||
end++; //to point behind the last null-char
|
||||
|
||||
|
||||
_data.erase(beg, end); //and remove the thingy
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
|
||||
seq.insert(seq.end(), id.begin(), id.end());
|
||||
seq.push_back('=');
|
||||
|
||||
|
||||
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
|
||||
|
||||
|
||||
if (itr == _data.end())
|
||||
return;//nothing to return if it's empty anyway...
|
||||
|
||||
|
||||
auto end = itr;
|
||||
|
||||
|
||||
while (*end != '\0')
|
||||
end++;
|
||||
|
||||
|
||||
end ++; //to point behind the last null-char
|
||||
|
||||
|
||||
_data.erase(itr, end);//and remove it
|
||||
reload();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
|
||||
{
|
||||
@@ -333,24 +333,24 @@ std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
|
||||
ret.push_back(nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T> constexpr T env_seperator();
|
||||
template<> constexpr char env_seperator() {return ';'; }
|
||||
template<> constexpr wchar_t env_seperator() {return L';'; }
|
||||
|
||||
|
||||
inline int get_id() {return boost::detail::winapi::GetCurrentProcessId();}
|
||||
inline void* native_handle() {return boost::detail::winapi::GetCurrentProcess(); }
|
||||
|
||||
|
||||
typedef void* native_handle_t;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
namespace detail { namespace windows {
|
||||
@@ -43,7 +42,7 @@ template<> struct startup_info<wchar_t>
|
||||
typedef ::boost::detail::winapi::STARTUPINFOW_ type;
|
||||
};
|
||||
|
||||
#if defined(DISABLED_FOR_NOW) && ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
|
||||
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
|
||||
|
||||
template<typename CharType> struct startup_info_ex;
|
||||
|
||||
@@ -62,12 +61,12 @@ template<> struct startup_info_ex<wchar_t>
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DISABLED_FOR_NOW) && ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
|
||||
#if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
|
||||
|
||||
template<typename CharT>
|
||||
struct startup_info_impl
|
||||
{
|
||||
::boost::detail::winapi::DWORD_ creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
|
||||
::boost::detail::winapi::DWORD_ creation_flags = 0;
|
||||
|
||||
typedef typename startup_info_ex<CharT>::type startup_info_ex_t;
|
||||
typedef typename startup_info<CharT>::type startup_info_t;
|
||||
@@ -80,7 +79,13 @@ struct startup_info_impl
|
||||
::boost::detail::winapi::invalid_handle_value},
|
||||
nullptr
|
||||
};
|
||||
startup_info_t & startup_info = startup_info_ex.StartupInfo;
|
||||
startup_info_t & startup_info = startup_info_ex.StartupInfo;
|
||||
|
||||
void set_startup_info_ex()
|
||||
{
|
||||
startup_info.cb = sizeof(startup_info_ex_t);
|
||||
creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -98,24 +103,19 @@ struct startup_info_impl
|
||||
::boost::detail::winapi::invalid_handle_value,
|
||||
::boost::detail::winapi::invalid_handle_value,
|
||||
::boost::detail::winapi::invalid_handle_value};
|
||||
|
||||
startup_info_t & get_startup_info() { return startup_info; }
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
class executor : public startup_info_impl<Char>
|
||||
{
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::false_, boost::mpl::true_) {}
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_, boost::mpl::true_) {}
|
||||
void internal_error_handle(const std::error_code &, const char*, boost::mpl::false_, boost::mpl::true_) {}
|
||||
void internal_error_handle(const std::error_code &, const char*, boost::mpl::true_, boost::mpl::true_) {}
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_, boost::mpl::false_ )
|
||||
void internal_error_handle(const std::error_code &ec, const char*, boost::mpl::true_, boost::mpl::false_ )
|
||||
{
|
||||
this->_ec = ec;
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
|
||||
|
||||
|
||||
#include <boost/detail/winapi/basic_types.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
enum mode_t
|
||||
@@ -37,18 +37,18 @@ struct file_descriptor
|
||||
return 0u;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
file_descriptor() = default;
|
||||
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
file_descriptor(const std::string & path , mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
file_descriptor(const std::wstring & path, mode_t mode = read_write)
|
||||
: file_descriptor(path.c_str(), mode) {}
|
||||
|
||||
|
||||
file_descriptor(const char* path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
::boost::detail::winapi::create_file(
|
||||
@@ -58,12 +58,12 @@ struct file_descriptor
|
||||
::boost::detail::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::detail::winapi::OPEN_ALWAYS_,
|
||||
|
||||
|
||||
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
file_descriptor(const wchar_t * path, mode_t mode = read_write)
|
||||
: _handle(
|
||||
@@ -74,31 +74,31 @@ struct file_descriptor
|
||||
::boost::detail::winapi::FILE_SHARE_WRITE_,
|
||||
nullptr,
|
||||
::boost::detail::winapi::OPEN_ALWAYS_,
|
||||
|
||||
|
||||
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
|
||||
nullptr
|
||||
))
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::detail::winapi::CloseHandle(_handle);
|
||||
}
|
||||
|
||||
|
||||
::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
|
||||
|
||||
|
||||
private:
|
||||
::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
|
||||
@@ -6,27 +6,27 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
#include <io.h>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct file_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::detail::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
|
||||
file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
@@ -38,7 +38,7 @@ struct file_in : public ::boost::process::detail::handler_base
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,32 +6,32 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor file;
|
||||
::boost::detail::winapi::HANDLE_ handle = file.handle();
|
||||
|
||||
|
||||
template<typename T>
|
||||
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
|
||||
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
|
||||
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
inline void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -39,12 +39,12 @@ void file_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -52,12 +52,12 @@ void file_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void file_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
@@ -65,13 +65,13 @@ void file_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
//does not extend anything.
|
||||
struct handler_base_ext : handler_base {};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
|
||||
|
||||
@@ -2,34 +2,34 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/windows/object_handle.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
|
||||
#include <boost/fusion/algorithm/transformation/transform.hpp>
|
||||
#include <boost/fusion/view/transform_view.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
{
|
||||
@@ -37,48 +37,48 @@ struct on_exit_handler_transformer
|
||||
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
|
||||
template<typename Sig>
|
||||
struct result;
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct result<on_exit_handler_transformer<Executor>(T&)>
|
||||
{
|
||||
typedef typename T::on_exit_handler_t type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
auto operator()(T& t) const -> typename T::on_exit_handler_t
|
||||
{
|
||||
return t.on_exit_handler(exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct async_handler_collector
|
||||
{
|
||||
Executor & exec;
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
|
||||
|
||||
|
||||
|
||||
|
||||
async_handler_collector(Executor & exec,
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
|
||||
: exec(exec), handlers(handlers) {}
|
||||
|
||||
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
handlers.push_back(t.on_exit_handler(exec));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//Also set's up waiting for the exit, so it can close async stuff.
|
||||
struct io_service_ref : boost::process::detail::handler_base
|
||||
{
|
||||
|
||||
|
||||
io_service_ref(boost::asio::io_service & ios)
|
||||
: ios(ios)
|
||||
{
|
||||
}
|
||||
boost::asio::io_service &get() {return ios;};
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec) const
|
||||
{
|
||||
@@ -86,39 +86,39 @@ struct io_service_ref : boost::process::detail::handler_base
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
>>(exec.seq);
|
||||
|
||||
|
||||
//ok, check if there are actually any.
|
||||
if (boost::fusion::empty(asyncs))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
|
||||
auto this_proc = ::boost::detail::winapi::GetCurrentProcess();
|
||||
|
||||
|
||||
auto proc_in = proc.hProcess;;
|
||||
::boost::detail::winapi::HANDLE_ process_handle;
|
||||
|
||||
|
||||
if (!::boost::detail::winapi::DuplicateHandle(
|
||||
this_proc, proc_in, this_proc, &process_handle, 0,
|
||||
static_cast<::boost::detail::winapi::BOOL_>(true),
|
||||
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
|
||||
|
||||
|
||||
exec.set_error(::boost::process::detail::get_last_error(),
|
||||
"Duplicate Pipe Failed");
|
||||
|
||||
|
||||
|
||||
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
funcs.reserve(boost::fusion::size(asyncs));
|
||||
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
|
||||
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
|
||||
|
||||
|
||||
auto handle_p = wh.handle.get();
|
||||
handle_p->async_wait(std::move(wh));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
struct wait_handler
|
||||
{
|
||||
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
|
||||
@@ -133,28 +133,28 @@ struct io_service_ref : boost::process::detail::handler_base
|
||||
handle(new boost::asio::windows::object_handle(ios, handle)),
|
||||
exit_status(exit_status)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
void operator()(const boost::system::error_code & ec_in)
|
||||
{
|
||||
std::error_code ec;
|
||||
if (ec_in)
|
||||
ec = std::error_code(ec_in.value(), std::system_category());
|
||||
|
||||
|
||||
::boost::detail::winapi::DWORD_ code;
|
||||
::boost::detail::winapi::GetExitCodeProcess(handle->native(), &code);
|
||||
exit_status->store(code);
|
||||
|
||||
|
||||
for (auto & func : funcs)
|
||||
func(code, ec);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
boost::asio::io_service &ios;
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_LOCALE_HPP_
|
||||
|
||||
|
||||
#include <locale>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/detail/winapi/file_management.hpp>
|
||||
#include <boost/detail/winapi/character_code_conversion.hpp>
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
@@ -20,7 +20,7 @@ namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
|
||||
//copied from boost.filesystem
|
||||
class windows_file_codecvt
|
||||
: public std::codecvt< wchar_t, char, std::mbstate_t >
|
||||
@@ -29,13 +29,13 @@ class windows_file_codecvt
|
||||
explicit windows_file_codecvt(std::size_t refs = 0)
|
||||
: std::codecvt<wchar_t, char, std::mbstate_t>(refs) {}
|
||||
protected:
|
||||
|
||||
|
||||
bool do_always_noconv() const noexcept override { return false; }
|
||||
|
||||
|
||||
// seems safest to assume variable number of characters since we don't
|
||||
// actually know what codepage is active
|
||||
int do_encoding() const noexcept override { return 0; }
|
||||
|
||||
|
||||
std::codecvt_base::result do_in(std::mbstate_t& state,
|
||||
const char* from, const char* from_end, const char*& from_next,
|
||||
wchar_t* to, wchar_t* to_end, wchar_t*& to_next) const override
|
||||
@@ -44,7 +44,7 @@ class windows_file_codecvt
|
||||
::boost::detail::winapi::UINT_ codepage = AreFileApisANSI() ?
|
||||
::boost::detail::winapi::CP_ACP_ :
|
||||
::boost::detail::winapi::CP_OEMCP_;
|
||||
|
||||
|
||||
int count;
|
||||
if ((count = ::boost::detail::winapi::MultiByteToWideChar(codepage,
|
||||
::boost::detail::winapi::MB_PRECOMPOSED_, from,
|
||||
@@ -52,13 +52,13 @@ class windows_file_codecvt
|
||||
{
|
||||
return error; // conversion failed
|
||||
}
|
||||
|
||||
|
||||
from_next = from_end;
|
||||
to_next = to + count;
|
||||
*to_next = L'\0';
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
std::codecvt_base::result do_out(std::mbstate_t & state,
|
||||
const wchar_t* from, const wchar_t* from_end, const wchar_t*& from_next,
|
||||
char* to, char* to_end, char*& to_next) const override
|
||||
@@ -67,7 +67,7 @@ class windows_file_codecvt
|
||||
auto codepage = ::boost::detail::winapi::AreFileApisANSI() ?
|
||||
::boost::detail::winapi::CP_ACP_ :
|
||||
::boost::detail::winapi::CP_OEMCP_;
|
||||
|
||||
|
||||
int count;
|
||||
if ((count = ::boost::detail::winapi::WideCharToMultiByte(codepage,
|
||||
::boost::detail::winapi::WC_NO_BEST_FIT_CHARS_, from,
|
||||
@@ -75,29 +75,29 @@ class windows_file_codecvt
|
||||
{
|
||||
return error; // conversion failed
|
||||
}
|
||||
|
||||
|
||||
from_next = from_end;
|
||||
to_next = to + count;
|
||||
*to_next = '\0';
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
std::codecvt_base::result do_unshift(std::mbstate_t&,
|
||||
char* /*from*/, char* /*to*/, char* & /*next*/) const override { return ok; }
|
||||
|
||||
|
||||
int do_length(std::mbstate_t&,
|
||||
const char* /*from*/, const char* /*from_end*/, std::size_t /*max*/) const override { return 0; }
|
||||
|
||||
|
||||
int do_max_length() const noexcept override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_IN_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct null_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor source{"NUL", file_descriptor::read};
|
||||
|
||||
|
||||
public:
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
@@ -29,13 +29,13 @@ public:
|
||||
boost::detail::winapi::SetHandleInformation(source.handle(),
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdInput = source.handle();
|
||||
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,27 +6,27 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_NULL_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/detail/winapi/handle_info.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/file_descriptor.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct null_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
file_descriptor sink {"NUL", file_descriptor::write}; //works because it gets destroyed AFTER launch.
|
||||
|
||||
|
||||
template <typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -34,13 +34,13 @@ void null_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -48,13 +48,13 @@ void null_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdError = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void null_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
@@ -62,14 +62,14 @@ void null_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(sink.handle(),
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = sink.handle();
|
||||
e.startup_info.hStdError = sink.handle();
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,40 +2,39 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct on_exit_ : boost::process::detail::windows::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
auto handler = this->handler;
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
|
||||
auto process_handle = proc.hProcess;
|
||||
return [handler, process_handle](int exit_code, const std::error_code & ec)
|
||||
return [handler](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
|
||||
@@ -6,30 +6,35 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_PIPE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
struct pipe_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::detail::winapi::HANDLE_ handle;
|
||||
template<typename T>
|
||||
pipe_in(const T & p) : handle(p.native_source()) {}
|
||||
|
||||
|
||||
pipe_in(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
|
||||
template<typename T> //async_pipe
|
||||
pipe_in(T & p) : handle(p.native_source())
|
||||
{
|
||||
p.assign_source(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
template <class WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const
|
||||
{
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdInput = handle;
|
||||
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
@@ -39,14 +44,46 @@ struct pipe_in : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class async_pipe;
|
||||
|
||||
struct async_pipe_in : public pipe_in
|
||||
{
|
||||
async_pipe &pipe;
|
||||
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_source()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).source().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,40 +7,46 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/handles.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct pipe_out : public ::boost::process::detail::handler_base
|
||||
{
|
||||
::boost::detail::winapi::HANDLE_ handle;
|
||||
|
||||
|
||||
pipe_out(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
|
||||
template<typename T>
|
||||
pipe_out(const T & p) : handle(p.native_sink()) {}
|
||||
|
||||
pipe_out(T & p) : handle(p.native_sink())
|
||||
{
|
||||
p.assign_sink(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
|
||||
}
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_setup(WindowsExecutor &e) const;
|
||||
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_error(WindowsExecutor &, const std::error_code &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
|
||||
|
||||
template<typename WindowsExecutor>
|
||||
void on_success(WindowsExecutor &) const
|
||||
{
|
||||
::boost::detail::winapi::CloseHandle(handle);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -48,12 +54,12 @@ void pipe_out<1,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
@@ -61,13 +67,13 @@ void pipe_out<2,-1>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
|
||||
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
template<typename WindowsExecutor>
|
||||
void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
@@ -75,13 +81,42 @@ void pipe_out<1,2>::on_setup(WindowsExecutor &e) const
|
||||
boost::detail::winapi::SetHandleInformation(handle,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
|
||||
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
|
||||
|
||||
|
||||
e.startup_info.hStdOutput = handle;
|
||||
e.startup_info.hStdError = handle;
|
||||
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
|
||||
e.inherit_handles = true;
|
||||
}
|
||||
|
||||
|
||||
template<int p1, int p2>
|
||||
struct async_pipe_out : public pipe_out<p1, p2>
|
||||
{
|
||||
async_pipe &pipe;
|
||||
template<typename AsyncPipe>
|
||||
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink()), pipe(p)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Pipe, typename Executor>
|
||||
static void close(Pipe & pipe, Executor &)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
std::move(pipe).sink().close(ec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_error(Executor & exec, const std::error_code &)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
void on_success(Executor &exec)
|
||||
{
|
||||
close(pipe, exec);
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,10 +31,11 @@ inline boost::filesystem::path search_path(
|
||||
{
|
||||
for (const boost::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
std::array<std::string, 4> extensions = { "", ".exe", ".com", ".bat" };
|
||||
auto full = pp / filename;
|
||||
std::array<std::string, 4> extensions {{ "", ".exe", ".com", ".bat" }};
|
||||
for (boost::filesystem::path ext : extensions)
|
||||
{
|
||||
auto p = full;
|
||||
p += ext;
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(p, ec);
|
||||
|
||||
@@ -7,17 +7,17 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
#define BOOST_PROCESS_WINDOWS_SHOW_WINDOW_HPP
|
||||
|
||||
|
||||
#include <boost/detail/winapi/process.hpp>
|
||||
#include <boost/detail/winapi/show_window.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<::boost::detail::winapi::WORD_ Flags>
|
||||
struct show_window : ::boost::process::detail::handler_base
|
||||
{
|
||||
@@ -28,12 +28,12 @@ struct show_window : ::boost::process::detail::handler_base
|
||||
e.startup_info.wShowWindow |= Flags;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -6,31 +6,31 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_START_DIR_HPP
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct start_dir_init : handler_base_ext
|
||||
{
|
||||
start_dir_init(const std::basic_string<Char> &s) : s_(s) {}
|
||||
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec) const
|
||||
{
|
||||
exec.work_dir = s_.c_str();
|
||||
}
|
||||
|
||||
|
||||
const std::basic_string<Char> &str() const {return s_;}
|
||||
private:
|
||||
std::basic_string<Char> s_;
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,114 +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_DETAIL_POSIX_VARIANT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_VARIANT_HPP_
|
||||
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <boost/variant/variant.hpp>
|
||||
#include <boost/variant/static_visitor.hpp>
|
||||
#include <boost/process/detail/async_handler.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace windows
|
||||
{
|
||||
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_setup(exec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_error_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
const std::error_code &ec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_error(exec, ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Executor>
|
||||
struct on_success_visitor : boost::static_visitor<void>
|
||||
{
|
||||
Executor & exec;
|
||||
|
||||
template<typename T>
|
||||
void operator()(T &t)
|
||||
{
|
||||
t.on_success(exec);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct variant_require_ios_tag_empty {};
|
||||
|
||||
template<typename ...Args>
|
||||
struct variant_require_ios_tag
|
||||
{
|
||||
using needs_io_service = typename needs_io_service<Args...>::type;
|
||||
using type = typename std::conditional<
|
||||
needs_io_service,
|
||||
require_io_service,
|
||||
variant_require_ios_tag_empty>::type;
|
||||
};
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
using variant_require_ios_tag_t = typename variant_require_ios_tag<Args...>::type;
|
||||
|
||||
template<typename ...Args>
|
||||
struct handler_variant : handler_base_ext, boost::variant<Args...>, variant_require_ios_tag_t<Args...>
|
||||
{
|
||||
using boost::variant<Args...>::variant;
|
||||
using boost::variant<Args...>::operator=;
|
||||
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
on_setup_visitor<Executor> vis{exec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor& exec, const std::error_code & ec)
|
||||
{
|
||||
on_error_visitor<Executor> vis{exec, ec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
void on_success(Executor& exec)
|
||||
{
|
||||
on_success_visitor<Executor> vis{exec};
|
||||
boost::apply_visitor(vis, *this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -2,19 +2,19 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
|
||||
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/none.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/env_init.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/env_init.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
/** \file boost/process/env.hpp
|
||||
*
|
||||
* This header which provides the `env` property. It allows the modification of the
|
||||
@@ -36,48 +36,48 @@ namespace boost {
|
||||
* - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
|
||||
namespace process { namespace detail {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const std::basic_string<Char> & ch)
|
||||
{
|
||||
return ch.size() + 1;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const Char * ch)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (ch[sz] != null_char<Char>())
|
||||
sz++;
|
||||
|
||||
|
||||
sz++;
|
||||
return sz;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char, typename Container>
|
||||
inline std::basic_string<Char> make_env_string(const Container & value)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
for (auto & v : value)
|
||||
sz += make_env_string_size(v);
|
||||
|
||||
|
||||
std::basic_string<Char> s;
|
||||
s.reserve(sz); //+1 for ;, end doesn't have one.
|
||||
|
||||
|
||||
for (auto & val : value)
|
||||
(s += val) += api::env_seperator<Char>();
|
||||
|
||||
|
||||
s.resize(s.size() -1); //remove last ';'
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_set
|
||||
{
|
||||
@@ -85,7 +85,7 @@ struct env_set
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_append
|
||||
{
|
||||
@@ -93,23 +93,23 @@ struct env_append
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_reset
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_set<wchar_t>>
|
||||
{
|
||||
@@ -119,7 +119,7 @@ struct char_converter<char, env_set<wchar_t>>
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_set<char>>
|
||||
{
|
||||
@@ -129,7 +129,7 @@ struct char_converter<wchar_t, env_set<char>>
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_append<wchar_t>>
|
||||
{
|
||||
@@ -139,7 +139,7 @@ struct char_converter<char, env_append<wchar_t>>
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_append<char>>
|
||||
{
|
||||
@@ -149,7 +149,7 @@ struct char_converter<wchar_t, env_append<char>>
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_reset<wchar_t>>
|
||||
{
|
||||
@@ -158,7 +158,7 @@ struct char_converter<char, env_reset<wchar_t>>
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_reset<char>>
|
||||
{
|
||||
@@ -167,14 +167,14 @@ struct char_converter<wchar_t, env_reset<char>>
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_init
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_init<wchar_t>>
|
||||
{
|
||||
@@ -183,7 +183,7 @@ struct char_converter<char, env_init<wchar_t>>
|
||||
return {basic_environment<char>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_init<char>>
|
||||
{
|
||||
@@ -192,15 +192,32 @@ struct char_converter<wchar_t, env_init<char>>
|
||||
return {basic_environment<wchar_t>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, basic_environment<wchar_t>>
|
||||
{
|
||||
static basic_environment<char> conv(const basic_environment<wchar_t> & in)
|
||||
{
|
||||
return { basic_environment<char>(in) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, basic_environment<char>>
|
||||
{
|
||||
static basic_environment<wchar_t> conv(const basic_environment<char> & in)
|
||||
{
|
||||
return { basic_environment<wchar_t>(in) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_proxy
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
|
||||
|
||||
|
||||
|
||||
env_set<Char> operator=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
@@ -213,7 +230,7 @@ struct env_proxy
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
|
||||
|
||||
env_append<Char> operator+=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
@@ -231,11 +248,11 @@ struct env_proxy
|
||||
return {std::move(key)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct env_
|
||||
{
|
||||
constexpr env_() {};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::basic_string<Char> & value) const
|
||||
@@ -280,16 +297,18 @@ struct env_
|
||||
return {env};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_builder
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
env_builder() : env{basic_native_environment<Char>()} {}
|
||||
|
||||
void operator()(const basic_environment<Char> & e)
|
||||
{
|
||||
env = e;
|
||||
}
|
||||
|
||||
|
||||
void operator()(env_init<Char> & ei)
|
||||
{
|
||||
env = std::move(ei.env);
|
||||
@@ -307,163 +326,163 @@ struct env_builder
|
||||
{
|
||||
env[es.key] += es.value;
|
||||
}
|
||||
|
||||
|
||||
typedef api::env_init<Char> result_type;
|
||||
api::env_init<Char> get_initializer()
|
||||
{
|
||||
return api::env_init<Char>(std::move(env));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<char>>
|
||||
{
|
||||
typedef env_builder<char> type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<wchar_t>>
|
||||
{
|
||||
typedef env_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
||||
|
||||
The `env` property provides a functional way to modify the environment used by
|
||||
the child process. If none is passed the environment is inherited from the father
|
||||
process. Appending means that the environment will be interpreted as a ';' or ':'
|
||||
seperated list as used in `PATH`.
|
||||
|
||||
|
||||
On both `posix` and `windows` the environment variables can be lists of strings,
|
||||
seperated by ';'. This is typically used for the `PATH` variable.
|
||||
|
||||
|
||||
By default the environment will be inherited from the launching process,
|
||||
which is also true if environment are modified with this initializer.
|
||||
|
||||
|
||||
\section env_details Details
|
||||
|
||||
|
||||
\subsection env_operations Operations
|
||||
|
||||
|
||||
\subsubsection env_set_var Setting variables
|
||||
|
||||
|
||||
To set a variable `id` the value `value` the following syntax can be used.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = value;
|
||||
env(id, value);
|
||||
\endcode
|
||||
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = {value1, value2};
|
||||
env(id, {value1, value2});
|
||||
\endcode
|
||||
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
|
||||
\paragraph id id
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
|
||||
\paragraph env_set_var_value value
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
|
||||
|
||||
\note Using `std::vector` or `std::initializer_list`
|
||||
|
||||
|
||||
\subsubsection env_append_var Append variables
|
||||
|
||||
|
||||
Appending means, that a variable will be interpreted as a
|
||||
To append a variable `id` the value `value` the following syntax can be used:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += value;
|
||||
\endcode
|
||||
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += {value1, value2};
|
||||
\endcode
|
||||
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
|
||||
\paragraph env_append_var_id id
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
|
||||
\paragraph env_append_var_value value
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
|
||||
|
||||
\subsubsection env_reset Reset variables
|
||||
|
||||
|
||||
Reseting signle variables can be done in the following way:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = boost::none;
|
||||
env(id, boost::none);
|
||||
\endcode
|
||||
|
||||
|
||||
\note This does not set the value empty, but removes it from the list.
|
||||
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
|
||||
|
||||
|
||||
\paragraph env_reset_var_id id
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
|
||||
\subsubsection env_init Initialize the environment
|
||||
|
||||
|
||||
The whole environment can be initialized from an object of type
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
env=env;
|
||||
env(env);
|
||||
\endcode
|
||||
|
||||
|
||||
\note The passed `environment` can also be default-constructed to get an empty environment.
|
||||
|
||||
|
||||
\paragraph env_init_var_id id
|
||||
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
|
||||
\paragraph env_init_var_value value
|
||||
|
||||
|
||||
- `boost::process::basic_environment<char_type>`
|
||||
|
||||
|
||||
\subsection env_example Example
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
|
||||
\endcode
|
||||
|
||||
|
||||
If the overload style should be done by passing an instance of
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
the above example would look like this.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
environment e = this_process::environment();
|
||||
e["PATH"] += "F:/boost";
|
||||
@@ -471,13 +490,13 @@ e.erase("SOME_VAR");
|
||||
e["NEW_VAR"] = "VALUE";
|
||||
spawn("b2", e);
|
||||
\endcode
|
||||
|
||||
|
||||
\warning Passing an empty environment will cause undefined behaviour.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static boost::process::detail::env_ env{};
|
||||
|
||||
|
||||
constexpr boost::process::detail::env_ env{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
|
||||
|
||||
@@ -139,8 +139,9 @@ struct entry : const_entry<Char, Environment>
|
||||
{
|
||||
string_type st = this->_data;
|
||||
this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
|
||||
|
||||
}
|
||||
|
||||
|
||||
this->reload();
|
||||
|
||||
}
|
||||
@@ -288,7 +289,7 @@ public:
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
return 1u;
|
||||
p++;
|
||||
}
|
||||
return 0u;
|
||||
@@ -296,20 +297,19 @@ public:
|
||||
void erase(const string_type & id)
|
||||
{
|
||||
implementation_type::reset(id);
|
||||
this->reload();
|
||||
}
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = id + ::boost::process::detail::equal_sign<Char>();
|
||||
auto f = find(id);
|
||||
if (f != end())
|
||||
if (f == end())
|
||||
{
|
||||
implementation_type::set(id, value);
|
||||
this->reload();
|
||||
return std::pair<iterator, bool>(find(id), true);
|
||||
|
||||
}
|
||||
else
|
||||
return std::pair<iterator, bool>(f, true);
|
||||
return std::pair<iterator, bool>(f, false);
|
||||
}
|
||||
using implementation_type::implementation_type;
|
||||
using implementation_type::operator=;
|
||||
@@ -326,8 +326,13 @@ public:
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
for (auto && i : *this)
|
||||
implementation_type::reset(i.get_name());
|
||||
std::vector<string_type> names;
|
||||
names.resize(size());
|
||||
std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
|
||||
|
||||
for (auto & nm : names)
|
||||
implementation_type::reset(nm);
|
||||
|
||||
this->reload();
|
||||
}
|
||||
|
||||
@@ -613,7 +618,7 @@ public:
|
||||
using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
};
|
||||
|
||||
///Type definition to hold a seperate environment.
|
||||
template<typename Char>
|
||||
@@ -663,11 +668,11 @@ inline wnative_environment wenvironment() { return ::boost::process::wnative_env
|
||||
inline std::vector<boost::filesystem::path> path()
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const ::boost::process::wnative_environment ne;
|
||||
const ::boost::process::wnative_environment ne{};
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
const auto id = L"PATH";
|
||||
#else
|
||||
const ::boost::process::native_environment ne;
|
||||
const ::boost::process::native_environment ne{};
|
||||
typedef typename ::boost::process::native_environment::const_entry_type value_type;
|
||||
const auto id = "PATH";
|
||||
#endif
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/algorithm/query/find_if.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/begin.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/end.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
#include <boost/fusion/sequence/comparison/equal_to.hpp>
|
||||
#include <boost/fusion/container/set/convert.hpp>
|
||||
#include <boost/type_index.hpp>
|
||||
@@ -104,21 +107,37 @@ template<> struct is_error_handler<throw_on_error_> : std::true_type {};
|
||||
template<> struct is_error_handler<ignore_error_> : std::true_type {};
|
||||
|
||||
|
||||
//note: is a tuple of pointers to initializers
|
||||
|
||||
template<typename Iterator, typename End>
|
||||
struct has_error_handler_impl
|
||||
{
|
||||
typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
|
||||
typedef typename std::remove_reference<ref_type>::type res_type_;
|
||||
typedef typename std::remove_cv<res_type_>::type res_type;
|
||||
typedef typename is_error_handler<res_type>::type cond;
|
||||
|
||||
typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
|
||||
typedef typename has_error_handler_impl<next_itr, End>::type next;
|
||||
|
||||
typedef typename boost::mpl::or_<cond, next>::type type;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct has_error_handler_impl<Iterator, Iterator>
|
||||
{
|
||||
typedef boost::mpl::false_ type;
|
||||
};
|
||||
|
||||
|
||||
template<typename Sequence>
|
||||
struct has_error_handler
|
||||
{
|
||||
|
||||
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, set_on_error>::type t1;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, set_on_error&>::type t2;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const set_on_error&>::type t3;
|
||||
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const throw_on_error_&>::type t4;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type t5;
|
||||
|
||||
typedef typename boost::mpl::or_<t1,t2,t3, t4, t5>::type type;
|
||||
typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type;
|
||||
|
||||
typedef typename has_error_handler_impl<
|
||||
typename boost::fusion::result_of::begin<vector_type>::type,
|
||||
typename boost::fusion::result_of::end< vector_type>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
@@ -129,7 +148,6 @@ struct has_ignore_error
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3;
|
||||
typedef typename boost::mpl::or_<type1,type2, type3>::type type;
|
||||
|
||||
};
|
||||
|
||||
struct error_builder
|
||||
@@ -156,10 +174,10 @@ struct initializer_builder<error_tag>
|
||||
}
|
||||
/**The ignore_error property will disable any error handling. This can be useful
|
||||
on linux, where error handling will require a pipe.*/
|
||||
constexpr static boost::process::detail::ignore_error_ ignore_error;
|
||||
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 static boost::process::detail::throw_on_error_ throw_on_error;
|
||||
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).
|
||||
@@ -181,11 +199,11 @@ The overload version is achieved by just passing an object of
|
||||
|
||||
|
||||
*/
|
||||
constexpr static boost::process::detail::error_ error;
|
||||
constexpr boost::process::detail::error_ error;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr static boost::process::detail::error_ error_ref;
|
||||
constexpr boost::process::detail::error_ error_ref;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr static boost::process::detail::error_ error_code;
|
||||
constexpr boost::process::detail::error_ error_code;
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -7,12 +7,12 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_EXE_HPP
|
||||
#define BOOST_PROCESS_EXE_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
|
||||
|
||||
/** \file boost/process/exe.hpp
|
||||
*
|
||||
* Header which provides the exe property.
|
||||
@@ -27,7 +27,7 @@ namespace boost {
|
||||
\endxmlonly
|
||||
*/
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
struct exe_
|
||||
{
|
||||
template<typename Char>
|
||||
@@ -40,7 +40,7 @@ struct exe_
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
@@ -52,28 +52,28 @@ struct exe_
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The exe property allows to explicitly set the executable.
|
||||
|
||||
|
||||
The overload form applies when to the first, when several strings are passed to a launching
|
||||
function.
|
||||
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
exe="value";
|
||||
exe(value);
|
||||
\endcode
|
||||
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::exe_ exe{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
339
include/boost/process/extend.hpp
Normal file
339
include/boost/process/extend.hpp
Normal file
@@ -0,0 +1,339 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXTENSIONS_HPP_
|
||||
#define BOOST_PROCESS_EXTENSIONS_HPP_
|
||||
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/posix/executor.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
/** \file boost/process/extend.hpp
|
||||
*
|
||||
* This header which provides the types and functions provided for custom extensions.
|
||||
*
|
||||
* \xmlonly
|
||||
Please refer to the <link linkend="boost_process.extend">tutorial</link> for more details.
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace detail {
|
||||
template<typename Tuple>
|
||||
inline asio::io_service& get_io_service(const Tuple & tup);
|
||||
}
|
||||
|
||||
|
||||
///Namespace for extensions \attention This is experimental.
|
||||
namespace extend {
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
using windows_executor = ::boost::process::detail::windows::executor<Char, Sequence>;
|
||||
template<typename Sequence>
|
||||
struct posix_executor;
|
||||
|
||||
#elif defined(BOOST_POSIX_API)
|
||||
|
||||
template<typename Sequence>
|
||||
using posix_executor = ::boost::process::detail::posix::executor<Sequence>;
|
||||
template<typename Char, typename Sequence>
|
||||
struct windows_executor;
|
||||
|
||||
#endif
|
||||
|
||||
using ::boost::process::detail::handler;
|
||||
using ::boost::process::detail::api::require_io_service;
|
||||
using ::boost::process::detail::api::async_handler;
|
||||
using ::boost::process::detail::get_io_service;
|
||||
using ::boost::process::detail::get_last_error;
|
||||
using ::boost::process::detail::throw_last_error;
|
||||
|
||||
///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
|
||||
///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error;
|
||||
///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success;
|
||||
|
||||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
|
||||
///This handler is invoked if the fork failed. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_fork_error_ > on_fork_error;
|
||||
///This handler is invoked if the fork succeeded. The required signature is `void(Exec &)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_setup_ > on_exec_setup;
|
||||
///This handler is invoked if the exec call errored. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_error_ > on_exec_error;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
///Helper function to get the last error code system-independent
|
||||
inline std::error_code get_last_error();
|
||||
|
||||
///Helper function to get and throw the last system error.
|
||||
/// \throws boost::process::process_error
|
||||
/// \param msg A message to add to the error code.
|
||||
inline void throw_last_error(const std::string & msg);
|
||||
///\overload void throw_last_error(const std::string & msg)
|
||||
inline void throw_last_error();
|
||||
|
||||
|
||||
/** This function gets the io_service from the initializer sequence.
|
||||
*
|
||||
* \attention Yields a compile-time error if no `io_service` is provided.
|
||||
* \param seq The Sequence of the initializer.
|
||||
*/
|
||||
template<typename Sequence>
|
||||
inline asio::io_service& get_io_service(const Sequence & seq);
|
||||
|
||||
/** This class is the base for every initializer, to be used for extensions.
|
||||
*
|
||||
* The usage is done through compile-time polymorphism, so that the required
|
||||
* functions can be overloaded.
|
||||
*
|
||||
* \note None of the function need to be `const`.
|
||||
*
|
||||
*/
|
||||
struct handler
|
||||
{
|
||||
///This function is invoked before the process launch. \note It is not required to be const.
|
||||
template <class Executor>
|
||||
void on_setup(Executor&) const {}
|
||||
|
||||
/** This function is invoked if an error occured while trying to launch the process.
|
||||
* \note It is not required to be const.
|
||||
*/
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code &) const {}
|
||||
|
||||
/** This function is invoked if the process was successfully launched.
|
||||
* \note It is not required to be const.
|
||||
*/
|
||||
template <class Executor>
|
||||
void on_success(Executor&) const {}
|
||||
|
||||
/**This function is invoked if an error occured during the call of `fork`.
|
||||
* \note This function will only be called on posix.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_fork_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
/**This function is invoked if the call of `fork` was successful, before
|
||||
* calling `execve`.
|
||||
* \note This function will only be called on posix.
|
||||
* \attention It will be invoked from the new process.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {}
|
||||
|
||||
/**This function is invoked if the call of `execve` failed.
|
||||
* \note This function will only be called on posix.
|
||||
* \attention It will be invoked from the new process.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_exec_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Inheriting the class will tell the launching process that an `io_service` is
|
||||
* needed. This should always be used when \ref get_io_service is used.
|
||||
*
|
||||
*/
|
||||
struct require_io_service {};
|
||||
/** Inheriting this class will tell the launching function, that an event handler
|
||||
* shall be invoked when the process exits. This automatically does also inherit
|
||||
* \ref require_io_service.
|
||||
*
|
||||
* You must add the following function to your implementation:
|
||||
*
|
||||
\code{.cpp}
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
auto handler = this->handler;
|
||||
return [handler](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
}
|
||||
\endcode
|
||||
|
||||
The callback will be obtained by calling this function on setup and it will be
|
||||
invoked when the process exits.
|
||||
|
||||
*
|
||||
* \warning Cannot be used with \ref boost::process::spawn
|
||||
*/
|
||||
struct async_handler : handler, require_io_service
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
///The posix executor type.
|
||||
/** This type represents the posix executor and can be used for overloading in a custom handler.
|
||||
* \note It is an alias for the implementation on posix, and a forward-declaration on windows.
|
||||
*
|
||||
* \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept.
|
||||
|
||||
|
||||
\xmlonly
|
||||
As information for extension development, here is the structure of the process launching (in pseudo-code and uml)
|
||||
<xi:include href="posix_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if when no error occurs.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_success.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if the execution fails.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_exec_err.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if the fork fails.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_fork_err.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
\endxmlonly
|
||||
|
||||
|
||||
\note Error handling if execve fails is done through a pipe, unless \ref ignore_error is used.
|
||||
|
||||
*/
|
||||
template<typename Sequence>
|
||||
struct posix_executor
|
||||
{
|
||||
///A reference to the actual initializer-sequence
|
||||
Sequence & seq;
|
||||
///A pointer to the name of the executable.
|
||||
const char * exe = nullptr;
|
||||
///A pointer to the argument-vector.
|
||||
char *const* cmd_line = nullptr;
|
||||
///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
|
||||
char **env = ::environ;
|
||||
///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */
|
||||
pid_t pid = -1;
|
||||
///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_service` and \ref child.
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
///This function returns a const reference to the error state of the executor.
|
||||
const std::error_code & error() const;
|
||||
|
||||
///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it
|
||||
/// might throw an exception. \note This is the required way to handle errors in initializers.
|
||||
void set_error(const std::error_code &ec, const std::string &msg);
|
||||
///\overload void set_error(const std::error_code &ec, const std::string &msg);
|
||||
void set_error(const std::error_code &ec, const char* msg);
|
||||
};
|
||||
|
||||
///The windows executor type.
|
||||
/** This type represents the posix executor and can be used for overloading in a custom handler.
|
||||
*
|
||||
* \note It is an alias for the implementation on posix, and a forward-declaration on windows.
|
||||
* \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept.
|
||||
* \tparam Char The used char-type, either `char` or `wchar_t`.
|
||||
*
|
||||
|
||||
\xmlonly
|
||||
As information for extension development, here is the structure of the process launching (in pseudo-code and uml)<xi:include href="windows_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence for windows process creation.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
\endxmlonly
|
||||
|
||||
*/
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
struct windows_executor
|
||||
{
|
||||
///A reference to the actual initializer-sequence
|
||||
Sequence & seq;
|
||||
|
||||
///A pointer to the name of the executable. It's null by default.
|
||||
const Char * exe = nullptr;
|
||||
///A pointer to the argument-vector. Must be set by some initializer.
|
||||
char Char* cmd_line = nullptr;
|
||||
///A pointer to the environment variables. It's null by default.
|
||||
char Char* env = nullptr;
|
||||
///A pointer to the working directory. It's null by default.
|
||||
const Char * work_dir = nullptr;
|
||||
|
||||
///A pointer to the process-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It's null by default.
|
||||
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
|
||||
///A pointer to the thread-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It' null by default.
|
||||
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
|
||||
///A logical bool value setting whether handles shall be inherited or not.
|
||||
::boost::detail::winapi::BOOL_ inherit_handles = false;
|
||||
|
||||
///The element holding the process-information after process creation. The type is [PROCESS_INFORMATION](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873.aspx)
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
|
||||
|
||||
|
||||
///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_service` and \ref child.
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
///This function returns a const reference to the error state of the executor.
|
||||
const std::error_code & error() const;
|
||||
|
||||
///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it
|
||||
/// might throw an exception. \note This is the required way to handle errors in initializers.
|
||||
void set_error(const std::error_code &ec, const std::string &msg);
|
||||
///\overload void set_error(const std::error_code &ec, const std::string &msg);
|
||||
void set_error(const std::error_code &ec, const char* msg);
|
||||
|
||||
///The creation flags of the process
|
||||
::boost::detail::winapi::DWORD_ creation_flags;
|
||||
///The type of the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx), depending on the char-type.
|
||||
typedef typename detail::startup_info<Char>::type startup_info_t;
|
||||
///The type of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx), depending the char-type; only defined with winapi-version equal or higher than 6.
|
||||
typedef typename detail::startup_info_ex<Char>::type startup_info_ex_t;
|
||||
///This function switches the information, so that the extended structure is used. \note It's only defined with winapi-version equal or higher than 6.
|
||||
void set_startup_info_ex();
|
||||
///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process.
|
||||
startup_info_t startup_info;
|
||||
///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6.
|
||||
startup_info_ex_t startup_info_ex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -55,6 +55,8 @@ namespace detail {
|
||||
* \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
|
||||
{
|
||||
@@ -120,7 +122,8 @@ public:
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
/** Wait for the process group to exit for period of time. */
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
@@ -134,7 +137,8 @@ public:
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
}
|
||||
|
||||
/** Wait for the process group to exit until a point in time. */
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
|
||||
@@ -2,20 +2,21 @@
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_IO_HPP_
|
||||
#define BOOST_PROCESS_IO_HPP_
|
||||
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
|
||||
|
||||
#include <future>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#include <boost/process/detail/posix/close_in.hpp>
|
||||
#include <boost/process/detail/posix/close_out.hpp>
|
||||
#include <boost/process/detail/posix/null_in.hpp>
|
||||
@@ -24,8 +25,8 @@
|
||||
#include <boost/process/detail/posix/file_out.hpp>
|
||||
#include <boost/process/detail/posix/pipe_in.hpp>
|
||||
#include <boost/process/detail/posix/pipe_out.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/detail/windows/close_in.hpp>
|
||||
#include <boost/process/detail/windows/close_out.hpp>
|
||||
#include <boost/process/detail/windows/null_in.hpp>
|
||||
@@ -34,9 +35,8 @@
|
||||
#include <boost/process/detail/windows/file_out.hpp>
|
||||
#include <boost/process/detail/windows/pipe_in.hpp>
|
||||
#include <boost/process/detail/windows/pipe_out.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
/** \file boost/process/io.hpp
|
||||
*
|
||||
* Header which provides the io properties. It provides the following properties:
|
||||
@@ -54,75 +54,75 @@ namespace boost {
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
|
||||
|
||||
\par File I/O
|
||||
|
||||
|
||||
The library allows full redirection of streams to files as shown below.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
boost::filesystem::path log = "my_log_file.txt";
|
||||
boost::filesystem::path input = "input.txt";
|
||||
boost::filesystem::path output = "output.txt";
|
||||
system("my_prog", std_out>output, std_in<input, std_err>log);
|
||||
\endcode
|
||||
|
||||
|
||||
\par Synchronous Pipe I/O
|
||||
|
||||
|
||||
Another way is to communicate through pipes.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
pstream str;
|
||||
child c("my_prog", std_out > str);
|
||||
|
||||
|
||||
int i;
|
||||
str >> i;
|
||||
\endcode
|
||||
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
|
||||
\par Asynchronous I/O
|
||||
|
||||
|
||||
Utilizing `boost.asio` asynchronous I/O is provided.
|
||||
|
||||
|
||||
\code
|
||||
boost::asio::io_service ios;
|
||||
std::future<std::string> output;
|
||||
system("ls", std_out > output, ios);
|
||||
|
||||
|
||||
auto res = fut.get();
|
||||
\endcode
|
||||
|
||||
|
||||
\note `boost/process/asnyc.hpp` must also be included for this to work.
|
||||
|
||||
|
||||
\par Closing
|
||||
|
||||
|
||||
Stream can be closed, so nothing can be read or written.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
system("foo", std_in.close());
|
||||
\endcode
|
||||
|
||||
|
||||
\par Null
|
||||
|
||||
|
||||
Streams can be redirected to null, which means, that written date will be
|
||||
discarded and read data will only contain `EOF`.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
system("b2", std_out > null);
|
||||
\endcode
|
||||
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
|
||||
template<typename T> using is_const_buffer =
|
||||
std::integral_constant<bool,
|
||||
@@ -134,66 +134,65 @@ template<typename T> using is_mutable_buffer =
|
||||
std::is_same< boost::asio::mutable_buffer, T>::value |
|
||||
std::is_base_of<boost::asio::mutable_buffer, T>::value
|
||||
>;
|
||||
|
||||
|
||||
|
||||
|
||||
struct null_t {constexpr null_t() {}};
|
||||
struct close_t;
|
||||
|
||||
|
||||
template<class>
|
||||
struct std_in_
|
||||
{
|
||||
constexpr std_in_() {}
|
||||
|
||||
|
||||
api::close_in close() const {return api::close_in(); }
|
||||
api::close_in operator=(const close_t &) const {return api::close_in();}
|
||||
api::close_in operator<(const close_t &) const {return api::close_in();}
|
||||
|
||||
|
||||
api::null_in null() const {return api::null_in();}
|
||||
api::null_in operator=(const null_t &) const {return api::null_in();}
|
||||
api::null_in operator<(const null_t &) const {return api::null_in();}
|
||||
|
||||
|
||||
api::file_in operator=(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator=(const std::string & p) const {return p;}
|
||||
api::file_in operator=(const std::wstring &p) const {return p;}
|
||||
api::file_in operator=(const char * p) const {return p;}
|
||||
api::file_in operator=(const wchar_t * p) const {return p;}
|
||||
|
||||
|
||||
api::file_in operator<(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator<(const std::string &p) const {return p;}
|
||||
api::file_in operator<(const std::wstring &p) const {return p;}
|
||||
api::file_in operator<(const char*p) const {return p;}
|
||||
api::file_in operator<(const wchar_t * p) const {return p;}
|
||||
|
||||
|
||||
api::file_in operator=(FILE * f) const {return f;}
|
||||
api::file_in operator<(FILE * f) const {return f;}
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(const basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(const basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(const basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(const basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(const basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(const basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::pipe_in operator=(const async_pipe & p) const {return p;}
|
||||
api::pipe_in operator<(const async_pipe & p) const {return p;}
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::async_pipe_in operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_in operator<(async_pipe & p) const {return p;}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator=(T & buf) const {return buf;}
|
||||
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator<(T & buf) const {return buf;}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-1 == empty.
|
||||
//1 == stdout
|
||||
//2 == stderr
|
||||
@@ -201,162 +200,162 @@ template<int p1, int p2 = -1>
|
||||
struct std_out_
|
||||
{
|
||||
constexpr std_out_() {}
|
||||
|
||||
|
||||
api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); }
|
||||
api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();}
|
||||
api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();}
|
||||
|
||||
|
||||
api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();}
|
||||
api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
|
||||
|
||||
api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
|
||||
api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
|
||||
api::file_out<p1,p2> operator=(FILE * f) const {return f;}
|
||||
api::file_out<p1,p2> operator>(FILE * f) const {return f;}
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(const basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(const basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(const basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(const basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(const basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(const basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::pipe_out<p1, p2> operator=(const async_pipe & p) const {return api::pipe_out<p1, p2>(p);}
|
||||
api::pipe_out<p1, p2> operator>(const async_pipe & p) const {return api::pipe_out<p1, p2>(p);}
|
||||
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
|
||||
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
|
||||
|
||||
|
||||
api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
|
||||
|
||||
|
||||
template<int pin, typename = typename std::enable_if<
|
||||
(((p1 == 1) && (pin == 2)) ||
|
||||
((p1 == 2) && (pin == 1)))
|
||||
&& (p2 == -1)>::type>
|
||||
constexpr std_out_<1, 2> operator& (const std_out_<pin> &lhs) const
|
||||
constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
|
||||
{
|
||||
return std_out_<1, 2> ();
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct close_t
|
||||
{
|
||||
constexpr close_t() {}
|
||||
template<int T, int U>
|
||||
api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams.
|
||||
constexpr static boost::process::detail::close_t close;
|
||||
constexpr boost::process::detail::close_t close;
|
||||
///This constant is a utility to redirect streams to the null-device.
|
||||
constexpr static boost::process::detail::null_t null;
|
||||
|
||||
constexpr boost::process::detail::null_t null;
|
||||
|
||||
/**
|
||||
This property allows to set the input stream for the child process.
|
||||
|
||||
|
||||
\section stdin_details Details
|
||||
|
||||
|
||||
\subsection stdin_file File Input
|
||||
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
|
||||
|
||||
with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
|
||||
FILE* is explicitly added, so the process can easily redirect the output stream
|
||||
of the child to another output stream of the process. That is:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
system("ls", std_in < stdin);
|
||||
\endcode
|
||||
|
||||
|
||||
\warning If the launching and the child process use the input, this leads to undefined behaviour.
|
||||
|
||||
|
||||
A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
|
||||
implementation not providing access to the handle.
|
||||
|
||||
|
||||
The valid expressions for this property are
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_in < file;
|
||||
std_in = file;
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdin_pipe Pipe Input
|
||||
|
||||
|
||||
As explained in the corresponding section, the boost.process library provides a
|
||||
@ref boost::process::async_pipe "async_pipe" class which can be
|
||||
used to communicate with child processes.
|
||||
|
||||
|
||||
\note Technically the @ref boost::process::async_pipe "async_pipe"
|
||||
works synchronous here, since no asio implementation is used by the library here.
|
||||
The async-operation will then however not end if the process is finished, since
|
||||
the pipe remains open. You can use the async_close function with on_exit to fix that.
|
||||
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_in < pipe;
|
||||
std_in = pipe;
|
||||
\endcode
|
||||
|
||||
|
||||
Where the valid types for `pipe` are the following:
|
||||
|
||||
|
||||
- `basic_pipe`
|
||||
- `async_pipe`
|
||||
- `basic_opstream`
|
||||
- `basic_pstream`
|
||||
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdin_async_pipe Asynchronous Pipe Input
|
||||
|
||||
|
||||
Asynchronous Pipe I/O classifies communication which has automatically handling
|
||||
of the asynchronous operations by the process library. This means, that a pipe will be
|
||||
constructed, the async_read/-write will be automatically started, and that the
|
||||
end of the child process will also close the pipe.
|
||||
|
||||
|
||||
Valid types for pipe I/O are the following:
|
||||
|
||||
|
||||
- `boost::asio::const_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::streambuf`
|
||||
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_in < buffer;
|
||||
std_in = buffer;
|
||||
@@ -367,7 +366,7 @@ std_err = buffer;
|
||||
(std_out & std_err) > buffer;
|
||||
(std_out & std_err) = buffer;
|
||||
\endcode
|
||||
|
||||
|
||||
\note It is also possible to get a future for std_in, by chaining another `std::future<void>` onto it,
|
||||
so you can wait for the input to be completed. It looks like this:
|
||||
\code{.cpp}
|
||||
@@ -377,129 +376,129 @@ std::string data;
|
||||
child c("prog", std_in < buffer(data) > fut, ios);
|
||||
fut.get();
|
||||
\endcode
|
||||
|
||||
|
||||
|
||||
|
||||
\note `boost::asio::buffer` is also available in the `boost::process` namespace.
|
||||
|
||||
|
||||
\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_service` to be passed to the launching function.
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection stdin_close Close
|
||||
|
||||
|
||||
The input stream can be closed, so it cannot be read from. This will lead to an error when attempted.
|
||||
|
||||
|
||||
This can be achieved by the following syntax.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_in < close;
|
||||
std_in = close;
|
||||
std_in.close();
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdin_null Null
|
||||
|
||||
|
||||
The input stream can be redirected to read from the null-device, which means that only `EOF` is read.
|
||||
|
||||
|
||||
The syntax to achieve that has the following variants:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_in < null;
|
||||
std_in = null;
|
||||
std_in.null();
|
||||
\endcode
|
||||
|
||||
|
||||
*/
|
||||
|
||||
constexpr static boost::process::detail::std_in_<void> std_in;
|
||||
|
||||
|
||||
constexpr boost::process::detail::std_in_<void> std_in;
|
||||
|
||||
/**
|
||||
This property allows to set the output stream for the child process.
|
||||
|
||||
|
||||
\note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly
|
||||
|
||||
|
||||
\note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`.
|
||||
|
||||
|
||||
\section stdout_details Details
|
||||
|
||||
|
||||
\subsection stdout_file File Input
|
||||
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
|
||||
|
||||
with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
|
||||
FILE* is explicitly added, so the process can easily redirect the output stream
|
||||
of the child to another output stream of the process. That is:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
system("ls", std_out < stdin);
|
||||
\endcode
|
||||
|
||||
|
||||
\warning If the launching and the child process use the input, this leads to undefined behaviour.
|
||||
|
||||
|
||||
A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
|
||||
implementation not providing access to the handle.
|
||||
|
||||
|
||||
The valid expressions for this property are
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_out < file;
|
||||
std_out = file;
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdout_pipe Pipe Output
|
||||
|
||||
|
||||
As explained in the corresponding section, the boost.process library provides a
|
||||
@ref boost::process::async_pipe "async_pipe" class which can be
|
||||
used to communicate with child processes.
|
||||
|
||||
|
||||
\note Technically the @ref boost::process::async_pipe "async_pipe"
|
||||
works like a synchronous pipe here, since no asio implementation is used by the library here.
|
||||
The asynchronous operation will then however not end if the process is finished, since
|
||||
the pipe remains open. You can use the async_close function with on_exit to fix that.
|
||||
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_out > pipe;
|
||||
std_out = pipe;
|
||||
\endcode
|
||||
|
||||
|
||||
Where the valid types for `pipe` are the following:
|
||||
|
||||
|
||||
- `basic_pipe`
|
||||
- `async_pipe`
|
||||
- `basic_ipstream`
|
||||
- `basic_pstream`
|
||||
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdout_async_pipe Asynchronous Pipe Output
|
||||
|
||||
|
||||
Asynchronous Pipe I/O classifies communication which has automatically handling
|
||||
of the async operations by the process library. This means, that a pipe will be
|
||||
constructed, the async_read/-write will be automatically started, and that the
|
||||
end of the child process will also close the pipe.
|
||||
|
||||
|
||||
Valid types for pipe I/O are the following:
|
||||
|
||||
|
||||
- `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::streambuf`
|
||||
- `std::future<std::vector<char>>`
|
||||
- `std::future<std::string>`
|
||||
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_out > buffer;
|
||||
std_out = buffer;
|
||||
@@ -508,45 +507,45 @@ std_err = buffer;
|
||||
(std_out & std_err) > buffer;
|
||||
(std_out & std_err) = buffer;
|
||||
\endcode
|
||||
|
||||
|
||||
\note `boost::asio::buffer` is also available in the `boost::process` namespace.
|
||||
|
||||
|
||||
\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_service` to be passed to the launching function.
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection stdout_close Close
|
||||
|
||||
|
||||
The out stream can be closed, so it cannot be write from.
|
||||
This will lead to an error when attempted.
|
||||
|
||||
|
||||
This can be achieved by the following syntax.
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_out > close;
|
||||
std_out = close;
|
||||
std_out.close();
|
||||
\endcode
|
||||
|
||||
|
||||
\subsection stdout_null Null
|
||||
|
||||
|
||||
The output stream can be redirected to write to the null-device,
|
||||
which means that all output is discarded.
|
||||
|
||||
|
||||
The syntax to achieve that has the following variants:
|
||||
|
||||
|
||||
\code{.cpp}
|
||||
std_out > null;
|
||||
std_out = null;
|
||||
std_out.null();
|
||||
\endcode
|
||||
|
||||
|
||||
*/
|
||||
|
||||
constexpr static boost::process::detail::std_out_<1> std_out;
|
||||
|
||||
constexpr boost::process::detail::std_out_<1> std_out;
|
||||
/**This property allows setting the `stderr` stream. The semantic and syntax is the same as for
|
||||
* \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly .
|
||||
*/
|
||||
constexpr static boost::process::detail::std_out_<2> std_err;
|
||||
|
||||
constexpr boost::process::detail::std_out_<2> std_err;
|
||||
|
||||
}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */
|
||||
|
||||
@@ -1,93 +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_IO_VARIANT_HPP_
|
||||
#define BOOST_PROCESS_IO_VARIANT_HPP_
|
||||
|
||||
#include <boost/process/variant.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using std_in_variant_base =
|
||||
handler_variant<
|
||||
api::null_in,
|
||||
api::close_in,
|
||||
api::pipe_in,
|
||||
api::file_in,
|
||||
api::async_in_buffer<boost::asio::mutable_buffer>,
|
||||
api::async_in_buffer<boost::asio::const_buffer>,
|
||||
api::async_in_buffer<boost::asio::mutable_buffers_1>,
|
||||
api::async_in_buffer<boost::asio::const_buffers_1>,
|
||||
api::async_in_buffer<boost::asio::streambuf>>;
|
||||
|
||||
template<int p1, int p2>
|
||||
using std_sink_variant_base =
|
||||
handler_variant<
|
||||
api::null_out<p1, p2>,
|
||||
api::close_out<p1, p2>,
|
||||
api::pipe_out<p1, p2>,
|
||||
api::file_out<p1, p2>,
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> ,
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1>,
|
||||
api::async_out_buffer<p1, p2, asio::streambuf>,
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer>,
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1>,
|
||||
api::async_out_buffer<p1, p2, asio::streambuf>,
|
||||
api::async_out_future<p1, p2, std::string>,
|
||||
api::async_out_future<p1, p2, std::string>,
|
||||
api::async_out_future<p1, p2, std::vector<char>>,
|
||||
api::async_out_future<p1, p2, std::vector<char>>>;
|
||||
|
||||
template<int p1, int p2 = -1>
|
||||
struct std_sink_variant : std_sink_variant_base<p1, p2>,
|
||||
::boost::process::detail::api::require_io_service
|
||||
{
|
||||
using std_sink_variant_base<p1, p2>::std_sink_variant_base;
|
||||
using std_sink_variant_base<p1, p2>::operator=;
|
||||
|
||||
void null() {*this = api:: null_out<p1, p2>();}
|
||||
void close() {*this = api::close_out<p1, p2>();}
|
||||
|
||||
template<typename T>
|
||||
void set(T& t)
|
||||
{
|
||||
*this = (std_out_<p1, p2>() > t);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct std_in_variant : detail::std_in_variant_base,
|
||||
::boost::process::detail::api::require_io_service
|
||||
{
|
||||
using detail::std_in_variant_base::std_in_variant_base;
|
||||
using detail::std_in_variant_base::operator=;
|
||||
|
||||
void null() {*this = detail::api:: null_in();}
|
||||
void close() {*this = detail::api::close_in();}
|
||||
|
||||
template<typename T>
|
||||
void set(T& t)
|
||||
{
|
||||
*this = (std_in < t);
|
||||
}
|
||||
};
|
||||
|
||||
using std_out_variant = ::boost::process::detail::std_sink_variant_base<1>;
|
||||
using std_err_variant = ::boost::process::detail::std_sink_variant_base<2>;
|
||||
using std_out_err_variant = ::boost::process::detail::std_sink_variant_base<1,2>;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,26 +2,29 @@
|
||||
// Copyright (c) 2008 Beman Dawes
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_LOCALE_HPP_
|
||||
#define BOOST_PROCESS_LOCALE_HPP_
|
||||
|
||||
|
||||
#include <system_error>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/locale.hpp>
|
||||
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
|
||||
|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||||
#include <codecvt>
|
||||
#endif
|
||||
|
||||
|
||||
#include <locale>
|
||||
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
class codecvt_category_t : public std::error_category
|
||||
{
|
||||
public:
|
||||
@@ -50,16 +53,16 @@ public:
|
||||
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
|
||||
@@ -71,32 +74,32 @@ inline std::locale default_locale()
|
||||
# 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::utf8_codecvt_facet);
|
||||
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
|
||||
# else // Other POSIX
|
||||
// ISO C calls std::locale("") "the locale-specific native environment", and this
|
||||
// locale is the default for many POSIX-based operating systems such as Linux.
|
||||
return std::locale("");
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
inline std::locale& process_locale()
|
||||
{
|
||||
static std::locale loc(default_locale());
|
||||
return loc;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
///The internally used type for code conversion.
|
||||
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
|
||||
|
||||
|
||||
///Get a reference to the currently used code converter.
|
||||
inline const codecvt_type& codecvt()
|
||||
{
|
||||
return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
|
||||
detail::process_locale());
|
||||
}
|
||||
|
||||
|
||||
///Set the locale of the library.
|
||||
inline std::locale imbue(const std::locale& loc)
|
||||
{
|
||||
@@ -104,11 +107,11 @@ inline std::locale imbue(const std::locale& loc)
|
||||
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,
|
||||
@@ -118,19 +121,19 @@ inline std::size_t convert(const char* from,
|
||||
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,
|
||||
@@ -140,17 +143,17 @@ inline std::size_t convert(const wchar_t* from,
|
||||
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())
|
||||
@@ -158,11 +161,11 @@ inline std::wstring convert(const std::string & st,
|
||||
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())
|
||||
@@ -170,11 +173,11 @@ inline std::string convert(const std::wstring & st,
|
||||
std::string out(st.size() * 2, ' '); //just to be sure
|
||||
auto sz = convert(st.c_str(), st.c_str() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
inline std::vector<wchar_t> convert(const std::vector<char> & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
@@ -182,11 +185,11 @@ inline std::vector<wchar_t> convert(const std::vector<char> & st,
|
||||
std::vector<wchar_t> out(st.size() + 10); //just to be sure
|
||||
auto sz = convert(st.data(), st.data() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
inline std::vector<char> convert(const std::vector<wchar_t> & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
@@ -194,12 +197,12 @@ inline std::vector<char> convert(const std::vector<wchar_t> & st,
|
||||
std::vector<char> out(st.size() * 2); //just to be sure
|
||||
auto sz = convert(st.data(), st.data() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
inline std::wstring convert(const char *begin, const char* end,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
@@ -212,32 +215,32 @@ inline std::wstring convert(const char *begin, const char* end,
|
||||
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_ */
|
||||
|
||||
@@ -67,6 +67,12 @@ public:
|
||||
/** 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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user