2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 04:42:24 +00:00

Compare commits

..

1 Commits

Author SHA1 Message Date
klemens-morgenstern
85345157d3 added (untested) initializer-variant. 2016-11-07 00:17:02 +01:00
487 changed files with 710058 additions and 3885 deletions

View File

@@ -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,8 +79,7 @@ before_install:
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
- git reset --hard; git clean -fxd
- git status
- echo "Removing $BOOST/libs/$BOOST_REMOVE"
- rm -rf $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
@@ -89,8 +88,8 @@ before_install:
script:
# `--coverage` flags required to generate coverage info for Coveralls
- ../../../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=.
- ../../../b2 testing.launcher=valgrind 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

View File

@@ -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), but will probably be released in boost 1.64. It is a library for comfortable management of processes.
Boost.process is not yet part of the [Boost C++ Libraries](http://github.com/boostorg). 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 on windows.
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.

View File

@@ -11,54 +11,21 @@ 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 ;

View File

@@ -1,82 +0,0 @@
[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]

View File

@@ -66,8 +66,7 @@ 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 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.]
[note On windows the path will only be searched for the executable in the command style.]
[endsect]
[section:plat_ext Extensions]

View File

@@ -1,211 +0,0 @@
[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]

View File

@@ -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]

View File

@@ -1,118 +0,0 @@
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

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -1 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 4.6 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.7 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.5 KiB

View File

@@ -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]

View File

@@ -1,60 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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>

View File

@@ -12,10 +12,8 @@
]
[include introduction.qbk]
[include concepts.qbk]
[include tutorial.qbk]
[include design.qbk]
[include extend.qbk]
[include faq.qbk]
[xinclude autodoc.xml]
[include acknowledgements.qbk]

View File

@@ -1,27 +1,20 @@
[def bp::system [funcref boost::process::system bp::system]]
[def bp::async_system [funcref boost::process::async_system bp::async_system]]
[def bp::spawn [funcref boost::process::spawn bp::spawn]]
[def bp::spawn [funcref boost::process::system 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]]
@@ -31,24 +24,22 @@
[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__ and the __concepts__ sections.
boost.process. For a full description see the __reference__.
[section Starting a process]
@@ -68,66 +59,55 @@ namespace bp = boost::process; //we will assume this for all further examples
int result = bp::system("g++ main.cpp");
```
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.
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.
```
int result = bp::system("/usr/bin/g++", "main.cpp");
int result = bp::system("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 = "/usr/bin/g++"; //or get it from somewhere else.
boost::filesystem::path p = "g++"; //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
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.
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.
```
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`.]
For more details please see the [link boost_process.design.arg_cmd_style design description].
[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 maybe unwanted,
our program will wait until the child process is completed. This is unwanted,
especially since compiling can take a while.
In order to avoid that, boost.process provides several ways to launch a process.
Besides the already mentioned [funcref boost::process::system system] function and it's
asynchronous version [funcref boost::process::async_system async_system],
Besides the already mentioned [funcref boost::process::system system] function,
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 it, so no handle will be returned and the process will be ignored.
immediately detaches so, 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(bp::search_path("chrome"), boost_org);
bp::spawn("chrome", boost_org);
```
Now for the more sensible approach for compiling: a non-blocking execution.
Now for the more sensible approach for compiling, we want a non-blocking execution.
To implement that, we directly call the constructor of [classref boost::process::child child].
```
bp::child c(bp::search_path("g++"), "main.cpp");
bp::child c("g++", "main.cpp");
while (c.child_running())
do_some_stuff();
@@ -158,7 +138,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]
@@ -168,20 +148,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++ main.cpp", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
bp::system("g++", 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.
@@ -200,7 +180,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(bp::search_patk("nm"), file, bp::std_out > is);
bp::child c("nm", file, bp::std_out > is);
std::vector<std::string> data;
std::string line;
@@ -248,20 +228,22 @@ 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(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);
bp::child nm("nm", file, bp::std_out > p);
bp::child filt("c++filt", bp::std_in < p, bp::std_out > is);
std::string line;
while (filt.running() && std::getline(is, line)) //when nm finished the pipe closes and c++filt exits
while (nm.running()) //nm finishes automatically, so then we can terminate c++filt.
{
std::string line;
std::getline(is, line);
outline.push_back(line);
}
nm.child_wait();
filt.wait();
filt.child_terminate();
}
```
This forwards the data from `nm` to `c++filt` without your process needing to do anything.
Now this forwards the data from `nm` to `c++filt` without your process needing to do anything.
[endsect]
[section:async_io Asynchronous I/O]
@@ -282,7 +264,7 @@ std::vector<char> buf;
bp::async_pipe ap(ios);
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > ap);
child c("g++", "main.cpp", bp::std_out > ap);
asio_async_read(ap, asio_buffer(buf),
[](const boost::system::error_code &ec, std::size_t size){});
@@ -299,7 +281,7 @@ provided we also pass a reference to an io_service.
io_service ios;
std::vector<char> buf;
bp::child c(bp::search_path("g++"), "main.cpp", bp::std_out > asio_buffer(buf), ios);
child c("g++", "main.cpp", bp::std_out > asio_buffer(buf), ios);
ios.run();
c.wait();
@@ -310,7 +292,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 or bp::async_system.
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system.
Now we will revisit our first example and read the compiler output asynchronously:
@@ -328,7 +310,7 @@ child c("g++", "main.cpp", //set the input
ios.run(); //this will actually block until the compiler is finished
auto err = data.get();
auto err = fut.get();
```
[endsect]
@@ -336,62 +318,18 @@ auto err = data.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 modify the group membership. E.g. if you call `make` which
if they do not modifiy 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::child c("make");
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
c.child_terminate(); //then terminate
```
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
bp::child c1("foo", g);
bp::child c2("bar", g);
g.group_terminate();
```
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.
Please see to the [headerref boost/process/group.hpp reference] for more information.
[endsect]
[section:env Environment]
@@ -407,22 +345,87 @@ env["VALUE_1"] = "foo";
//copy it into a environment seperate to the one of this process
bp::environment env_ = env;
//append two values to a variable in the new env
env_["VALUE_2"] += {"bar1", "bar2"};
//add a value only to the new env
env_["VALUE_2"] = "bar";
//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, which the example as following:
```
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
```
[globalref boost::process::env env] property.
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]

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<programlisting>
for (auto &amp; 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 &amp; 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 &amp; 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 &amp; 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 &amp; 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>

View File

@@ -15,7 +15,7 @@ using namespace boost::process;
int main()
{
ipstream pipe_stream;
child c("gcc --version", std_out > pipe_stream);
child c("gcc.exe", "--version", std_out > pipe_stream);
std::string line;

View File

@@ -9,38 +9,37 @@
#include <boost/process.hpp>
#include <boost/process/posix.hpp>
#include <boost/process/extend.hpp>
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <errno.h>
namespace bp = boost::process;
using namespace boost::process;
int main()
{
//duplicate our pipe descriptor into literal position 4
bp::pipe p;
bp::system("test", bp::posix::fd.bind(4, p.native_sink()));
pipe p;
system("test", posix::fd.bind(4, p.native_sink()) );
//close file-descriptor from explicit integral value
bp::system("test", bp::posix::fd.close(STDIN_FILENO));
system("test", posix::fd.close(STDIN_FILENO));
//close file-descriptors from explicit integral values
bp::system("test", bp::posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
system("test", posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
//add custom handlers
const char *env[2] = { 0 };
env[0] = "LANG=de";
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)
system("test",
on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
posix::on_fork_error([](auto&)
{ std::cerr << errno << std::endl; }),
bp::extend::on_exec_setup([](auto&)
posix::on_exec_setup([](auto&)
{ ::chroot("/new/root/directory/"); }),
bp::extend::on_exec_error([](auto&, const std::error_code & ec)
posix::on_exec_error([](auto&)
{ std::ofstream ofs("log.txt"); if (ofs) ofs << errno; })
);

View File

@@ -21,7 +21,6 @@
#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>

View File

@@ -101,24 +101,15 @@ on_exit=function;
on_exit(function);
\endcode
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
`std::future<int>`.
with `function` being a callable object with the signature `(int, const std::error_code&)`.
\par Example
\code{.cpp}
io_service ios;
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
std::future<int> exit_code;
chlid c2("ls", on_exit=exit_code);
spawn("ls", on_exit=[](int exit, const std::error_code& ec_in){});
\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

View File

@@ -160,22 +160,26 @@ 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](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
* See the boost.asio documentation for more details.
*/
template<typename MutableBufferSequence,
typename ReadHandler>
detail::dummy async_read_some(
BOOST_ASIO_INITFN_RESULT_TYPE(
ReadHandler, void(boost::system::error_code, std::size_t))
async_read_some(
const MutableBufferSequence & buffers,
ReadHandler &&handler);
/** Start an asynchronous write.
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
* See the boost.asio documentation for more details.
*/
template<typename ConstBufferSequence,
typename WriteHandler>
detail::dummy async_write_some(
BOOST_ASIO_INITFN_RESULT_TYPE(
WriteHandler, void(boost::system::error_code, std::size_t))
async_write_some(
const ConstBufferSequence & buffers,
WriteHandler && handler);

View File

@@ -1,142 +0,0 @@
// 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

View File

@@ -99,16 +99,13 @@ class child
/** \overload void wait() */
void wait(std::error_code & ec) noexcept;
/** Wait for the child process to exit for a period of time.
* \return True if child exited while waiting.
*/
/** Wait for the child process to exit for a period of time. */
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
/** Wait for the child process to exit until a point in time.
* \return True if child exited while waiting.*/
/** Wait for the child process to exit until a point in time. */
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 )*/

View File

@@ -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

View File

@@ -97,14 +97,49 @@ 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>
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, 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)
{
return f;
}
template<typename First, typename ...Args>
boost::asio::io_service &get_io_service_var(First&, Args&...args)
boost::asio::io_service &get_io_service_var(First & f, Args&...args)
{
return get_io_service_var(args...);
}

View File

@@ -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> conv(const arg_setter_<char, false> & in)
static arg_setter_<wchar_t, false> conv2(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 /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */

View File

@@ -25,11 +25,7 @@
#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
@@ -78,19 +74,19 @@ inline void throw_last_error()
}
template<typename Char> constexpr Char null_char();
template<typename Char> constexpr static Char null_char();
template<> constexpr char null_char<char> (){return '\0';}
template<> constexpr wchar_t null_char<wchar_t> (){return L'\0';}
template<typename Char> constexpr Char equal_sign();
template<typename Char> constexpr static Char equal_sign();
template<> constexpr char equal_sign<char> () {return '='; }
template<> constexpr wchar_t equal_sign<wchar_t> () {return L'='; }
template<typename Char> constexpr Char quote_sign();
template<typename Char> constexpr static Char quote_sign();
template<> constexpr char quote_sign<char> () {return '"'; }
template<> constexpr wchar_t quote_sign<wchar_t> () {return L'"'; }
template<typename Char> constexpr Char space_sign();
template<typename Char> constexpr static Char space_sign();
template<> constexpr char space_sign<char> () {return ' '; }
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }

View File

@@ -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 ::boost::process::detail::make_builders_from_view<
typedef typename detail::make_builders_from_view<
typename boost::fusion::result_of::begin<others_t>::type,
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
builder_t builders;
::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
detail::builder_ref<builder_t> builder_ref(builders);
boost::fusion::for_each(others, builder_ref);
auto other_inits = ::boost::process::detail::get_initializers(builders);

View File

@@ -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,13 +63,16 @@ 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_ */

View File

@@ -18,7 +18,6 @@ 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>

View File

@@ -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_ */

View File

@@ -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,35 +61,34 @@ 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){});
std::move(*pipe).source().close();
::close(pipe->native_source());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).source().close();
::close(pipe->native_source());
}
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

View File

@@ -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;
std::move(*pipe).sink().close();
::close(pipe->native_sink());
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
::close(pipe->native_sink());
}
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,14 +113,12 @@ 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() != ENOENT))
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
@@ -134,37 +132,37 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
promise->set_value(std::move(arg));
}
});
std::move(*pipe).sink().close();
::close(pipe->native_sink());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
::close(pipe->native_sink());
}
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

View File

@@ -19,8 +19,8 @@ class async_pipe
::boost::asio::posix::stream_descriptor _source;
::boost::asio::posix::stream_descriptor _sink ;
public:
typedef int native_handle_type;
typedef ::boost::asio::posix::stream_descriptor handle_type;
typedef int native_handle;
typedef ::boost::asio::posix::stream_descriptor handle_type;
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
@@ -124,8 +124,9 @@ public:
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
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();}
template<typename MutableBufferSequence,
typename ReadHandler>
@@ -153,17 +154,19 @@ public:
const handle_type & sink () const & {return _sink;}
const handle_type & source() const & {return _source;}
handle_type && sink() && { return std::move(_sink); }
handle_type && source()&& { return std::move(_source); }
handle_type && source()&& { return std::move(_sink); }
handle_type && sink() && { return std::move(_source); }
handle_type source(::boost::asio::io_service& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _source.release());
::boost::asio::posix::stream_descriptor stolen(ios, _source.native_handle());
_source.assign(-1);
return stolen;
}
handle_type sink (::boost::asio::io_service& ios) &&
{
::boost::asio::posix::stream_descriptor stolen(ios, _sink.release());
::boost::asio::posix::stream_descriptor stolen(ios, _sink.native_handle());
_sink.assign(-1);
return stolen;
}
@@ -306,7 +309,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
::boost::process::detail::throw_last_error("dup()");
}
return basic_pipe<CharT, Traits>{source, sink};
return {source, sink};
}

View File

@@ -110,11 +110,8 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
template <class Executor>
void on_setup(Executor& exec)
{
if (exe.empty()) //cmd style
{
if (exe.empty())
exec.exe = args.front().c_str();
exec.cmd_style = true;
}
else
exec.exe = &exe.front();

View File

@@ -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_type;
typedef int native_handle;
basic_pipe()
{
@@ -71,13 +71,8 @@ public:
if (_source != -1)
::close(_source);
}
native_handle_type native_source() const {return _source;}
native_handle_type native_sink () const {return _sink;}
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
native_handle native_source() const {return _source;}
native_handle native_sink () const {return _sink;}
int_type write(const char_type * data, int_type count)

View File

@@ -22,6 +22,7 @@ namespace posix
{
template<typename Char>
inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value)
{
@@ -60,9 +61,7 @@ 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
{

View File

@@ -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,41 +105,40 @@ public:
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload() {this->_env_impl = ::environ;}
void reload() {}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto res = ::setenv(id, value, 1);
auto val = std::string(id) + "=" + value;
auto res = ::setenv(id, value, true);
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
{
@@ -156,21 +155,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)
@@ -181,7 +180,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,
@@ -193,11 +192,11 @@ public:
{
return ::boost::process::detail::convert(st, cv);
}
);
reload();
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
@@ -206,26 +205,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
{
@@ -237,7 +236,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 "";
@@ -245,7 +244,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)
{
@@ -257,15 +256,19 @@ 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)
{
@@ -283,40 +286,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_ */

View File

@@ -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_DETAIL_POSIX_EXECUTOR_HPP
#define BOOST_PROCESS_POSIX_EXECUTOR_HPP
#include <boost/process/detail/child_decl.hpp>
#include <boost/process/error.hpp>
@@ -22,47 +22,9 @@
#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
{
@@ -143,19 +105,6 @@ 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)
{
@@ -168,9 +117,8 @@ 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);
}
@@ -240,6 +188,7 @@ 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_ );
@@ -316,7 +265,6 @@ 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);
@@ -348,10 +296,7 @@ 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));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
::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);
@@ -403,10 +348,8 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
::close(p[0]);
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
::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));
@@ -420,16 +363,12 @@ 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));
@@ -451,6 +390,7 @@ 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)
{
@@ -466,6 +406,7 @@ 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));
@@ -484,7 +425,6 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
return child();
}
_ec.clear();
this->pid = ::vfork();
if (pid == -1)
{
@@ -499,11 +439,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
{
boost::fusion::for_each(seq, call_on_exec_setup(*this));
if (cmd_style)
::boost::process::detail::posix::execvpe(exe, cmd_line, env);
else
::execve(exe, cmd_line, env);
::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));
@@ -511,17 +447,15 @@ 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));

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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

View File

@@ -2,48 +2,49 @@
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
//does not extend anything.
struct handler_base_ext : handler_base
{
template<typename Executor>
void on_fork_error (Executor &, const std::error_code&) const {}
template<typename Executor>
void on_exec_setup (Executor &) const {}
template<typename Executor>
void on_exec_error (Executor &, const std::error_code&) const {}
};
template <class Handler>
struct on_fork_error_ : handler_base_ext
{
explicit on_fork_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_fork_error(Executor &e, const std::error_code &ec) const
void on_fork_error(Executor &e) const
{
handler_(e, ec);
handler_(e);
}
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
{
@@ -52,23 +53,27 @@ 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 std::error_code &ec) const
void on_exec_error(Executor &e) const
{
handler_(e, ec);
handler_(e);
}
private:
Handler handler_;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_ */

View File

@@ -2,30 +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_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
{
@@ -33,89 +34,77 @@ 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)
void on_setup(Executor& exec) const
{
//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));
//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));
}
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(
@@ -125,31 +114,49 @@ 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(status);
exit_status->store(val);
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_ */

View File

@@ -14,7 +14,7 @@
namespace boost { namespace process { namespace detail { namespace posix {
constexpr int still_active = 0x7F;
constexpr static int still_active = 0x7F;
static_assert(!WIFEXITED(still_active), "Internal Error");
inline bool is_running(const child_handle &p, int & exit_code)

View File

@@ -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

View File

@@ -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

View File

@@ -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_ */

View File

@@ -6,85 +6,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_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
{
int source;
int sink; //opposite end
pipe_in(int sink, int source) : source(source), sink(sink) {}
int descr_;
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
{
p.assign_source(-1);
}
pipe_in(const T & p) : descr_(p.native_source()) {}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(source);
::close(descr_);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(source);
::close(descr_);
}
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
if (::dup2(descr_, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
::close(sink);
::close(descr_);
}
};
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

View File

@@ -7,110 +7,70 @@
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
pipe_out(int sink, int source) : sink(sink), source(source) {}
int descr_;
template<typename T>
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
{
p.assign_sink(-1);
}
pipe_out(const T & p) : descr_(p.native_sink()) {}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(sink);
::close(descr_);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(sink);
::close(descr_);
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
if (::dup2(descr_, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(sink);
::close(source);
::close(descr_);
}
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
if (::dup2(descr_, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
::close(descr_);
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
if (::dup2(descr_, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
if (::dup2(descr_, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
::close(descr_);
}
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

View File

@@ -16,17 +16,9 @@
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&)
@@ -55,16 +47,16 @@ struct sig_init_ : handler_base_ext
}
private:
bool _reset = false;
::boost::process::detail::posix::sighandler_t _old{0};
::boost::process::detail::posix::sighandler_t _handler{0};
::sighandler_t _old{0};
::sighandler_t _handler{0};
};
struct sig_
{
constexpr sig_() {}
sig_init_ operator()(::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator= (::boost::process::detail::posix::sighandler_t h) const {return h;}
sig_init_ operator()(::sighandler_t h) const {return h;}
sig_init_ operator= (::sighandler_t h) const {return h;}
sig_init_ dfl() const {return SIG_DFL;}
sig_init_ ign() const {return SIG_IGN;}

View File

@@ -0,0 +1,157 @@
// 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

View File

@@ -141,6 +141,8 @@ inline bool wait_until(
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
@@ -175,6 +177,8 @@ inline bool wait_until(
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{

View File

@@ -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& exec, const std::error_code & ec) const
void on_error(Executor&, 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 boost::process::detail::throw_on_error_ throw_on_error;
constexpr static boost::process::detail::throw_on_error_ throw_on_error;
}}

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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,72 +14,69 @@
#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_ */

View File

@@ -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,11 +66,15 @@ 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_ */

View File

@@ -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_ */

View File

@@ -2,26 +2,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_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_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 initializer_tag<std::error_code>;
struct make_initializer_t<error_tag>;
template<> struct initializer_tag_t<std::error_code> { typedef error_tag type;};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -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_GROUP_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_GROUP_HPP_
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>

View File

@@ -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* > : std::true_type {};
template<> struct is_wchar_t<wchar_t* > { typedef std::true_type 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 = 0;
std::size_t sz;
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 = 0;
std::size_t sz;
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 = 0;
std::size_t sz;
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 = 0;
std::size_t sz;
while (st[sz] != L'\0') sz++;
return convert(st, st + sz);
});

View File

@@ -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_ */

View File

@@ -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&)
inline void on_success(Executor &exec)
{
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&, std::size_t){});
std::move(*pipe).source().close();
[pipe](const boost::system::error_code&ec, std::size_t size){});
::boost::detail::winapi::CloseHandle(pipe->native_source());
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

View File

@@ -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&)
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){});
std::move(*pipe).sink().close();
[pipe](const boost::system::error_code&, std::size_t size){});
::boost::detail::winapi::CloseHandle(pipe->native_sink());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
::boost::detail::winapi::CloseHandle(pipe->native_sink());
}
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&)
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
std::move(*pipe).sink().close();
::boost::detail::winapi::CloseHandle(pipe->native_sink());
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t)
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
{
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
{
std::move(*pipe).sink().close();
::boost::detail::winapi::CloseHandle(pipe->native_sink());
}
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

View File

@@ -100,26 +100,20 @@ public:
if (_sink.is_open())
{
_sink.close();
_sink = handle_type(_sink.get_io_service());
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
if (_source.is_open())
{
_source.close();
_source = handle_type(_source.get_io_service());
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
}
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
@@ -351,23 +345,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_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
if (source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return basic_pipe<CharT, Traits>{source, sink};
return {source, sink};
}
inline bool operator==(const async_pipe & lhs, const async_pipe & rhs)

View File

@@ -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_ */

View File

@@ -55,9 +55,6 @@ 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))

View File

@@ -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_>(0),
static_cast<::boost::detail::winapi::BOOL_>(1),
pid);
if (h == nullptr)

View File

@@ -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_ */

View File

@@ -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,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};
::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};
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");

View File

@@ -8,7 +8,6 @@
#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>
@@ -25,11 +24,6 @@ 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
@@ -38,11 +32,10 @@ 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()),
"Empty Environment");
"Bad Environment");
}
exec.env = e;
exec.creation_flags |= creation_flag(Char());
}
};

View File

@@ -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(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");
throw process_error("GetEnvironmentVariable() failed",
std::error_code(err, std::system_category()));
}
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_ */

View File

@@ -24,6 +24,7 @@
#include <atomic>
#include <cstring>
namespace boost { namespace process {
namespace detail { namespace windows {
@@ -42,7 +43,7 @@ template<> struct startup_info<wchar_t>
typedef ::boost::detail::winapi::STARTUPINFOW_ type;
};
#if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6
#if defined(DISABLED_FOR_NOW) && ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
template<typename CharType> struct startup_info_ex;
@@ -61,12 +62,12 @@ template<> struct startup_info_ex<wchar_t>
#endif
#if ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
#if defined(DISABLED_FOR_NOW) && ( BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 )
template<typename CharT>
struct startup_info_impl
{
::boost::detail::winapi::DWORD_ creation_flags = 0;
::boost::detail::winapi::DWORD_ creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
typedef typename startup_info_ex<CharT>::type startup_info_ex_t;
typedef typename startup_info<CharT>::type startup_info_t;
@@ -79,13 +80,7 @@ struct startup_info_impl
::boost::detail::winapi::invalid_handle_value},
nullptr
};
startup_info_t & startup_info = startup_info_ex.StartupInfo;
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
creation_flags = ::boost::detail::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
startup_info_t & startup_info = startup_info_ex.StartupInfo;
};
@@ -103,19 +98,24 @@ 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 &, 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::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 &ec, const char*, boost::mpl::true_, boost::mpl::false_ )
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_, boost::mpl::false_ )
{
this->_ec = ec;
}

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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

View File

@@ -2,39 +2,40 @@
//
// Distributed under the Boost Software License, 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&)
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)
::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)
{
handler(static_cast<int>(exit_code), ec);
};
}
};
}}}}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */

View File

@@ -6,35 +6,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_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;
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<typename T>
pipe_in(const T & p) : handle(p.native_source()) {}
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;
@@ -44,46 +39,14 @@ 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

View File

@@ -7,46 +7,40 @@
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_PIPE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base
{
::boost::detail::winapi::HANDLE_ handle;
pipe_out(::boost::detail::winapi::HANDLE_ handle) : handle(handle) {}
template<typename T>
pipe_out(T & p) : handle(p.native_sink())
{
p.assign_sink(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
pipe_out(const T & p) : handle(p.native_sink()) {}
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
@@ -54,12 +48,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
@@ -67,13 +61,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
@@ -81,42 +75,13 @@ 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

View File

@@ -32,7 +32,7 @@ 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" }};
std::array<std::string, 4> extensions = { "", ".exe", ".com", ".bat" };
for (boost::filesystem::path ext : extensions)
{
p += ext;

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,114 @@
// 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

View File

@@ -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,32 +192,15 @@ 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};
@@ -230,7 +213,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};
@@ -248,11 +231,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
@@ -297,18 +280,16 @@ 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);
@@ -326,163 +307,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";
@@ -490,13 +471,13 @@ e.erase("SOME_VAR");
e["NEW_VAR"] = "VALUE";
spawn("b2", e);
\endcode
\warning Passing an empty environment will cause undefined behaviour.
*/
constexpr boost::process::detail::env_ env{};
constexpr static boost::process::detail::env_ env{};
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */

View File

@@ -139,9 +139,8 @@ 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();
}
@@ -289,7 +288,7 @@ public:
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
return 1u;
break;
p++;
}
return 0u;
@@ -297,19 +296,20 @@ 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, false);
return std::pair<iterator, bool>(f, true);
}
using implementation_type::implementation_type;
using implementation_type::operator=;
@@ -326,13 +326,8 @@ public:
}
void clear()
{
std::vector<string_type> names;
names.resize(size());
std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
for (auto & nm : names)
implementation_type::reset(nm);
for (auto && i : *this)
implementation_type::reset(i.get_name());
this->reload();
}
@@ -618,7 +613,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>
@@ -668,11 +663,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

View File

@@ -25,10 +25,7 @@
#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>
@@ -107,37 +104,21 @@ template<> struct is_error_handler<throw_on_error_> : std::true_type {};
template<> struct is_error_handler<ignore_error_> : std::true_type {};
template<typename Iterator, typename End>
struct has_error_handler_impl
{
typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
typedef typename std::remove_reference<ref_type>::type res_type_;
typedef typename std::remove_cv<res_type_>::type res_type;
typedef typename is_error_handler<res_type>::type cond;
typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
typedef typename has_error_handler_impl<next_itr, End>::type next;
typedef typename boost::mpl::or_<cond, next>::type type;
};
template<typename Iterator>
struct has_error_handler_impl<Iterator, Iterator>
{
typedef boost::mpl::false_ type;
};
//note: is a tuple of pointers to initializers
template<typename Sequence>
struct has_error_handler
{
typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type;
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 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>
@@ -148,6 +129,7 @@ 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
@@ -174,10 +156,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 boost::process::detail::ignore_error_ ignore_error;
constexpr static boost::process::detail::ignore_error_ ignore_error;
/**The throw_on_error property will enable the exception when launching a process.
It is unnecessary by default, but may be used, when an additional error_code is provided.*/
constexpr boost::process::detail::throw_on_error_ throw_on_error;
constexpr static 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).
@@ -199,11 +181,11 @@ The overload version is achieved by just passing an object of
*/
constexpr boost::process::detail::error_ error;
constexpr static boost::process::detail::error_ error;
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
constexpr boost::process::detail::error_ error_ref;
constexpr static boost::process::detail::error_ error_ref;
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
constexpr boost::process::detail::error_ error_code;
constexpr static boost::process::detail::error_ error_code;
}}

View File

@@ -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

View File

@@ -1,339 +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_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

View File

@@ -55,8 +55,6 @@ 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
{
@@ -122,8 +120,7 @@ public:
{
boost::process::detail::api::wait(_group_handle, ec);
}
/** Wait for the process group to exit for period of time.
* \return True if all child processes exited while waiting.*/
/** Wait for the process group to exit for period of time. */
template< class Rep, class Period >
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
@@ -137,8 +134,7 @@ 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.
* \return True if all child processes exited while waiting.*/
/** Wait for the process group to exit until a point in time. */
template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{

View File

@@ -2,21 +2,20 @@
//
// Distributed under the Boost Software License, 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>
@@ -25,8 +24,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>
@@ -35,8 +34,9 @@
#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,65 +134,66 @@ 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=(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 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 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
@@ -200,162 +201,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=(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;}
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);}
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
template<int pin, typename = typename std::enable_if<
(((p1 == 1) && (pin == 2)) ||
((p1 == 2) && (pin == 1)))
&& (p2 == -1)>::type>
constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
constexpr std_out_<1, 2> operator& (const std_out_<pin> &lhs) const
{
return std_out_<1, 2> ();
}
};
struct close_t
{
constexpr close_t() {}
template<int T, int U>
api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
};
}
///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams.
constexpr boost::process::detail::close_t close;
constexpr static boost::process::detail::close_t close;
///This constant is a utility to redirect streams to the null-device.
constexpr boost::process::detail::null_t null;
constexpr static 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;
@@ -366,7 +367,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}
@@ -376,129 +377,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 boost::process::detail::std_in_<void> std_in;
constexpr static 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;
@@ -507,45 +508,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 boost::process::detail::std_out_<1> std_out;
constexpr static boost::process::detail::std_out_<1> std_out;
/**This property allows setting the `stderr` stream. The semantic and syntax is the same as for
* \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly .
*/
constexpr boost::process::detail::std_out_<2> std_err;
constexpr static boost::process::detail::std_out_<2> std_err;
}}
#endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */

View File

@@ -0,0 +1,93 @@
// 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

View File

@@ -2,29 +2,26 @@
// 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:
@@ -53,16 +50,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
@@ -74,32 +71,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::codecvt_utf8<wchar_t>);
return std::locale(global_loc, new std::utf8_codecvt_facet);
# 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)
{
@@ -107,11 +104,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,
@@ -121,19 +118,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,
@@ -143,17 +140,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())
@@ -161,11 +158,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())
@@ -173,11 +170,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())
@@ -185,11 +182,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())
@@ -197,12 +194,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())
@@ -215,32 +212,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_ */

View File

@@ -67,12 +67,6 @@ 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