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

Compare commits

..

2 Commits

Author SHA1 Message Date
klemens-morgenstern
248af92cfa startet on experimental optoins impl. not sure it's worth it though. 2016-11-07 00:20:30 +01:00
klemens-morgenstern
85345157d3 added (untested) initializer-variant. 2016-11-07 00:17:02 +01:00
532 changed files with 716137 additions and 10162 deletions

96
.gitattributes vendored
View File

@@ -1,96 +0,0 @@
* text=auto !eol svneol=native#text/plain
*.gitattributes text svneol=native#text/plain
# Scriptish formats
*.bat text svneol=native#text/plain
*.bsh text svneol=native#text/x-beanshell
*.cgi text svneol=native#text/plain
*.cmd text svneol=native#text/plain
*.js text svneol=native#text/javascript
*.php text svneol=native#text/x-php
*.pl text svneol=native#text/x-perl
*.pm text svneol=native#text/x-perl
*.py text svneol=native#text/x-python
*.sh eol=lf svneol=LF#text/x-sh
configure eol=lf svneol=LF#text/x-sh
# Image formats
*.bmp binary svneol=unset#image/bmp
*.gif binary svneol=unset#image/gif
*.ico binary svneol=unset#image/ico
*.jpeg binary svneol=unset#image/jpeg
*.jpg binary svneol=unset#image/jpeg
*.png binary svneol=unset#image/png
*.tif binary svneol=unset#image/tiff
*.tiff binary svneol=unset#image/tiff
*.svg text svneol=native#image/svg%2Bxml
# Data formats
*.pdf binary svneol=unset#application/pdf
*.avi binary svneol=unset#video/avi
*.doc binary svneol=unset#application/msword
*.dsp text svneol=crlf#text/plain
*.dsw text svneol=crlf#text/plain
*.eps binary svneol=unset#application/postscript
*.gz binary svneol=unset#application/gzip
*.mov binary svneol=unset#video/quicktime
*.mp3 binary svneol=unset#audio/mpeg
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
*.ps binary svneol=unset#application/postscript
*.psd binary svneol=unset#application/photoshop
*.rdf binary svneol=unset#text/rdf
*.rss text svneol=unset#text/xml
*.rtf binary svneol=unset#text/rtf
*.sln text svneol=native#text/plain
*.swf binary svneol=unset#application/x-shockwave-flash
*.tgz binary svneol=unset#application/gzip
*.vcproj text svneol=native#text/xml
*.vcxproj text svneol=native#text/xml
*.vsprops text svneol=native#text/xml
*.wav binary svneol=unset#audio/wav
*.xls binary svneol=unset#application/vnd.ms-excel
*.zip binary svneol=unset#application/zip
# Text formats
.htaccess text svneol=native#text/plain
*.bbk text svneol=native#text/xml
*.cmake text svneol=native#text/plain
*.css text svneol=native#text/css
*.dtd text svneol=native#text/xml
*.htm text svneol=native#text/html
*.html text svneol=native#text/html
*.ini text svneol=native#text/plain
*.log text svneol=native#text/plain
*.mak text svneol=native#text/plain
*.qbk text svneol=native#text/plain
*.rst text svneol=native#text/plain
*.sql text svneol=native#text/x-sql
*.txt text svneol=native#text/plain
*.xhtml text svneol=native#text/xhtml%2Bxml
*.xml text svneol=native#text/xml
*.xsd text svneol=native#text/xml
*.xsl text svneol=native#text/xml
*.xslt text svneol=native#text/xml
*.xul text svneol=native#text/xul
*.yml text svneol=native#text/plain
boost-no-inspect text svneol=native#text/plain
CHANGES text svneol=native#text/plain
COPYING text svneol=native#text/plain
INSTALL text svneol=native#text/plain
Jamfile text svneol=native#text/plain
Jamroot text svneol=native#text/plain
Jamfile.v2 text svneol=native#text/plain
Jamrules text svneol=native#text/plain
Makefile* text svneol=native#text/plain
README text svneol=native#text/plain
TODO text svneol=native#text/plain
# Code formats
*.c text svneol=native#text/plain
*.cpp text svneol=native#text/plain
*.h text svneol=native#text/plain
*.hpp text svneol=native#text/plain
*.ipp text svneol=native#text/plain
*.tpp text svneol=native#text/plain
*.jam text svneol=native#text/plain
*.java text svneol=native#text/plain

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
@@ -65,7 +65,7 @@ before_install:
- BOOST=$HOME/boost-local
- git init $BOOST
- cd $BOOST
- if [ $BRANCH_TO_TEST = "master" ]; then
- if [ $(BRANCH_TO_TEST) = "master" ]; then
BOOST_BRANCH=master;
else BOOST_BRANCH=develop; fi
- git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
@@ -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 with-valgrind 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 without-valgrind 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,13 +1,13 @@
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
#[Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
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
Branches | Build | Tests coverage |
----------------|-------------- | -------------- |
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop)](https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=develop)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) |
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master)](https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master)] (https://travis-ci.org/klemens-morgenstern/boost-process) [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
@@ -21,4 +21,4 @@ Distributed under the [Boost Software License, Version 1.0](http://www.boost.org
### Dependency
This library requires boost 1.64 with which it is released.
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 its 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,212 +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
}
};
```
[caution All async_handlers use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_service`]
[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,87 +1,87 @@
[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)
{
ipstream is;
opstream os;
child c("c++filt", std_out > is, std_in < os);
vector<string> data;
for (auto & elem : data)
{
string line;
getline(is, line);
os << elem;
}
}
```
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 waits for its 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())
{
is >> file;
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]
[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)
{
ipstream is;
opstream os;
child c("c++filt", std_out > is, std_in < os);
vector<string> data;
for (auto & elem : data)
{
string line;
getline(is, line);
os << elem;
}
}
```
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())
{
is >> file;
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 syntax we still have "g++" hard-coded, so let's assume we get the string
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 its
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_path("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]
@@ -278,11 +260,11 @@ With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what
```
io_service ios;
std::vector<char> buf(4096);
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 to 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 its 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 occurs. 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]
@@ -405,24 +343,89 @@ auto env = boost::this_process::environment();
//add a variable to the current environment
env["VALUE_1"] = "foo";
//copy it into an environment separate to the one of this process
//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

@@ -16,7 +16,7 @@ namespace bp = boost::process;
int main()
{
boost::asio::io_context ios;
boost::asio::io_service ios;
boost::asio::streambuf buffer;

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

@@ -44,14 +44,14 @@ int main()
}
{
boost::asio::io_context io_context;
bp::async_pipe p1(io_context);
bp::async_pipe p2(io_context);
boost::asio::io_service io_service;
bp::async_pipe p1(io_service);
bp::async_pipe p2(io_service);
bp::system(
"test.exe",
bp::std_out > p2,
bp::std_in < p1,
io_context,
io_service,
bp::on_exit([&](int exit, const std::error_code& ec_in)
{
p1.async_close();
@@ -64,7 +64,7 @@ int main()
boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){});
}
{
boost::asio::io_context io_context;
boost::asio::io_service io_service;
std::vector<char> in_buf;
std::string value = "my_string";
bp::system(
@@ -75,7 +75,7 @@ int main()
}
{
boost::asio::io_context io_context;
boost::asio::io_service io_service;
std::future<std::vector<char>> in_buf;
std::future<void> write_fut;
std::string value = "my_string";

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,14 +21,14 @@ int main()
}
{
boost::asio::io_context io_context;
boost::asio::io_service io_service;
bp::child c(
"test.exe",
io_context,
io_service,
bp::on_exit([&](int exit, const std::error_code& ec_in){})
);
io_context.run();
io_service.run();
}
}

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

@@ -7,7 +7,7 @@
The header which provides the basic asynchrounous features.
It provides the on_exit property, which allows callbacks when the process exits.
It also implements the necessary traits for passing an boost::asio::io_context,
It also implements the necessary traits for passing an boost::asio::io_service,
which is needed for asynchronous communication.
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
@@ -32,20 +32,20 @@ namespace boost {
#include <boost/process/detail/traits.hpp>
#include <boost/process/detail/on_exit.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
#include <boost/fusion/iterator/deref.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/io_context_ref.hpp>
#include <boost/process/detail/posix/io_service_ref.hpp>
#include <boost/process/detail/posix/async_in.hpp>
#include <boost/process/detail/posix/async_out.hpp>
#include <boost/process/detail/posix/on_exit.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/io_context_ref.hpp>
#include <boost/process/detail/windows/io_service_ref.hpp>
#include <boost/process/detail/windows/async_in.hpp>
#include <boost/process/detail/windows/async_out.hpp>
#include <boost/process/detail/windows/on_exit.hpp>
@@ -56,25 +56,25 @@ namespace boost { namespace process { namespace detail {
struct async_tag;
template<typename T>
struct is_io_context : std::false_type {};
struct is_io_service : std::false_type {};
template<>
struct is_io_context<api::io_context_ref> : std::true_type {};
struct is_io_service<api::io_service_ref> : std::true_type {};
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup)
inline asio::io_service& get_io_service(const Tuple & tup)
{
auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup);
auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup);
return ref.get();
}
struct async_builder
{
boost::asio::io_context * ios;
boost::asio::io_service * ios;
void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;};
void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;};
typedef api::io_context_ref result_type;
api::io_context_ref get_initializer() {return api::io_context_ref (*ios);};
typedef api::io_service_ref result_type;
api::io_service_ref get_initializer() {return api::io_service_ref (*ios);};
};
@@ -90,7 +90,7 @@ using ::boost::asio::buffer;
#if defined(BOOST_PROCESS_DOXYGEN)
/** When an io_context is passed, the on_exit property can be used, to be notified
/** When an io_service is passed, the on_exit property can be used, to be notified
when the child process exits.
@@ -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_context 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);
io_service ios;
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 get invoked on error.
\warning All `on_exit` use one signal(SIGCHLD) on posix, which is only guaranteed to work when all use the same `io_context`.
*/
constexpr static ::boost::process::detail::on_exit_ on_exit{};
#endif

View File

@@ -48,31 +48,31 @@ public:
typedef platform_specific handle_type;
/** Construct a new async_pipe, does automatically open the pipe.
* Initializes source and sink with the same io_context.
* Initializes source and sink with the same io_service.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_context & ios);
inline async_pipe(boost::asio::io_service & ios);
/** Construct a new async_pipe, does automatically open the pipe.
* @note Windows creates a named pipe here, where the name is automatically generated.
*/
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink);
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink);
/** Construct a new async_pipe, does automatically open.
* Initializes source and sink with the same io_context.
* Initializes source and sink with the same io_service.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_context & ios, const std::string & name);
inline async_pipe(boost::asio::io_service & ios, const std::string & name);
/** Construct a new async_pipe, does automatically open.
*
* @note Windows restricts possible names.
*/
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink, const std::string & name);
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink, const std::string & name);
/** Copy-Constructor of the async pipe.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
@@ -89,15 +89,15 @@ public:
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p);
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p);
/** Construct the async-pipe from a pipe, with two different io_context objects.
/** Construct the async-pipe from a pipe, with two different io_service objects.
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
*
*/
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
explicit async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p);
@@ -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);
@@ -189,15 +193,15 @@ public:
///Get the asio handle of the pipe source. Qualified as rvalue
handle_type && source() &&;
/// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_context& ios) &&;
/// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_context& ios) &&;
/// Move the source out of this class and change the io_service. Qualified as rvalue. \attention Will always move.
handle_type source(::boost::asio::io_service& ios) &&;
/// Move the sink out of this class and change the io_service. Qualified as rvalue. \attention Will always move
handle_type sink (::boost::asio::io_service& ios) &&;
/// Copy the source out of this class and change the io_context. \attention Will always copy.
handle_type source(::boost::asio::io_context& ios) const &;
/// Copy the sink out of this class and change the io_context. \attention Will always copy
handle_type sink (::boost::asio::io_context& ios) const &;
/// Copy the source out of this class and change the io_service. \attention Will always copy.
handle_type source(::boost::asio::io_service& ios) const &;
/// Copy the sink out of this class and change the io_service. \attention Will always copy
handle_type sink (::boost::asio::io_service& ios) const &;

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_context & ios;
boost::asio::async_completion<
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_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(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.completion_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.completion_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_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
*/
#if defined(BOOST_PROCESS_DOXYGEN)
template<typename ExitHandler, typename ...Args>
inline boost::process::detail::dummy
async_system(boost::asio::io_context & 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_context & 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

@@ -35,9 +35,6 @@ child::child(Args&&...args)
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
///Typedef for the type of an pid_t
typedef ::boost::process::detail::api::pid_t pid_t;
#if defined(BOOST_PROCESS_DOXYGEN)
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
* in that it has a join and detach function.
@@ -102,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

@@ -1,122 +1,122 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#include <boost/winapi/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/cmd.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/cmd.hpp>
#endif
/** \file boost/process/cmd.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
}
}
</programlisting>
\endxmlonly
*/
namespace boost { namespace process { namespace detail {
struct cmd_
{
constexpr cmd_() {}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
};
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, api::cmd_setter_<wchar_t>>
{
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
template<>
struct char_converter<wchar_t, api::cmd_setter_<char>>
{
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
}
/** The cmd property allows to explicitly set commands for the execution.
The overload form applies when only one string is passed to a launching function.
The string will be internally parsed and split at spaces.
The following expressions are valid, with `value` being either a C-String or
a `std::basic_string` with `char` or `wchar_t`.
\code{.cpp}
cmd="value";
cmd(value);
\endcode
The property can only be used for assignments.
*/
constexpr static ::boost::process::detail::cmd_ cmd;
}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
#include <boost/detail/winapi/config.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/cmd.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/cmd.hpp>
#endif
/** \file boost/process/cmd.hpp
*
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
*
\xmlonly
<programlisting>
namespace boost {
namespace process {
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
}
}
</programlisting>
\endxmlonly
*/
namespace boost { namespace process { namespace detail {
struct cmd_
{
constexpr cmd_() {}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const Char *s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
template<typename Char>
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
{
return api::cmd_setter_<Char>(s);
}
};
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, api::cmd_setter_<wchar_t>>
{
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
template<>
struct char_converter<wchar_t, api::cmd_setter_<char>>
{
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
{
return { ::boost::process::detail::convert(in.str()) };
}
};
}
/** The cmd property allows to explicitly set commands for the execution.
The overload form applies when only one string is passed to a launching function.
The string will be internally parsed and split at spaces.
The following expressions are valid, with `value` being either a C-String or
a `std::basic_string` with `char` or `wchar_t`.
\code{.cpp}
cmd="value";
cmd(value);
\endcode
The property can only be used for assignments.
*/
constexpr static ::boost::process::detail::cmd_ cmd;
}}
#endif

View File

@@ -27,37 +27,37 @@ namespace detail {
#if defined(BOOST_POSIX_API)
using ::boost::process::detail::posix::is_async_handler;
using ::boost::process::detail::posix::does_require_io_context;
using ::boost::process::detail::posix::does_require_io_service;
#else
using ::boost::process::detail::windows::is_async_handler;
using ::boost::process::detail::windows::does_require_io_context;
using ::boost::process::detail::windows::does_require_io_service;
#endif
template<typename ...Args>
struct has_io_context;
struct has_io_service;
template<typename T, typename ...Args>
struct has_io_context<T, Args...>
struct has_io_service<T, Args...>
{
typedef typename has_io_context<Args...>::type next;
typedef typename has_io_service<Args...>::type next;
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_context>::type is_ios;
boost::asio::io_service>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct has_io_context<T>
struct has_io_service<T>
{
typedef typename std::is_same<
typename std::remove_reference<T>::type,
boost::asio::io_context>::type type;
boost::asio::io_service>::type type;
};
template<typename ...Args>
using has_io_context_t = typename has_io_context<Args...>::type;
using has_io_service_t = typename has_io_service<Args...>::type;
template<typename ...Args>
struct has_async_handler;
@@ -79,34 +79,69 @@ struct has_async_handler<T>
};
template<typename ...Args>
struct needs_io_context;
struct needs_io_service;
template<typename T, typename ...Args>
struct needs_io_context<T, Args...>
struct needs_io_service<T, Args...>
{
typedef typename needs_io_context<Args...>::type next;
typedef typename does_require_io_context<T>::type is_ios;
typedef typename needs_io_service<Args...>::type next;
typedef typename does_require_io_service<T>::type is_ios;
typedef typename std::conditional<is_ios::value,
std::true_type,
next>::type type;
};
template<typename T>
struct needs_io_context<T>
struct needs_io_service<T>
{
typedef typename does_require_io_context<T>::type type;
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_context &get_io_context_var(boost::asio::io_context & 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_context &get_io_context_var(First&, Args&...args)
boost::asio::io_service &get_io_service_var(First & f, Args&...args)
{
return get_io_context_var(args...);
return get_io_service_var(args...);
}
}

View File

@@ -1,292 +1,292 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined( BOOST_WINDOWS_API )
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#include <boost/process/shell.hpp>
#include <iterator>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct exe_setter_
{
typedef Char value_type;
typedef std::basic_string<Char> string_type;
string_type exe_;
exe_setter_(string_type && str) : exe_(std::move(str)) {}
exe_setter_(const string_type & str) : exe_(str) {}
};
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template <typename Char, bool Append >
struct arg_setter_
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
std::vector<string_type> _args;
typedef typename std::vector<string_type>::iterator iterator;
typedef typename std::vector<string_type>::const_iterator const_iterator;
template<typename Iterator>
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
template<typename Range>
arg_setter_(Range && str) :
_args(std::begin(str),
std::end(str)) {}
iterator begin() {return _args.begin();}
iterator end() {return _args.end();}
const_iterator begin() const {return _args.begin();}
const_iterator end() const {return _args.end();}
arg_setter_(string_type & str) : _args{{str}} {}
arg_setter_(string_type && s) : _args({std::move(s)}) {}
arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
template<std::size_t Size>
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
};
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
template<>
struct char_converter<char, arg_setter_<wchar_t, true>>
{
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<wchar_t, arg_setter_<char, true>>
{
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<char, arg_setter_<wchar_t, false>>
{
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
template<>
struct char_converter<wchar_t, arg_setter_<char, false>>
{
static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
using api::exe_cmd_init;
template<typename Char>
struct exe_builder
{
//set by path, because that will not be interpreted as a cmd
bool not_cmd = false;
bool shell = false;
using string_type = std::basic_string<Char>;
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
exe = data.native();
else
args.push_back(data.native());
}
void operator()(const string_type & data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(const Char* data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(shell_) {shell = true;}
void operator()(std::vector<string_type> && data)
{
if (data.empty())
return;
auto itr = std::make_move_iterator(data.begin());
auto end = std::make_move_iterator(data.end());
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(const std::vector<string_type> & data)
{
if (data.empty())
return;
auto itr = data.begin();
auto end = data.end();
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(exe_setter_<Char> && data)
{
not_cmd = true;
exe = std::move(data.exe_);
}
void operator()(const exe_setter_<Char> & data)
{
not_cmd = true;
exe = data.exe_;
}
void operator()(arg_setter_<Char, false> && data)
{
args.assign(
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(arg_setter_<Char, true> && data)
{
args.insert(args.end(),
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(const arg_setter_<Char, false> & data)
{
args.assign(data._args.begin(), data._args.end());
}
void operator()(const arg_setter_<Char, true> & data)
{
args.insert(args.end(), data._args.begin(), data._args.end());
}
api::exe_cmd_init<Char> get_initializer()
{
if (not_cmd || !args.empty())
{
if (shell)
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
else
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
}
else
if (shell)
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
else
return api::exe_cmd_init<Char>::cmd(std::move(exe));
}
typedef api::exe_cmd_init<Char> result_type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>
{
typedef exe_builder<char> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
{
typedef exe_builder<wchar_t> type;
};
}}}
#endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#if defined( BOOST_WINDOWS_API )
#include <boost/process/detail/windows/basic_cmd.hpp>
#include <boost/process/detail/windows/cmd.hpp>
#elif defined( BOOST_POSIX_API )
#include <boost/process/detail/posix/basic_cmd.hpp>
#include <boost/process/detail/posix/cmd.hpp>
#endif
#include <boost/process/shell.hpp>
#include <iterator>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct exe_setter_
{
typedef Char value_type;
typedef std::basic_string<Char> string_type;
string_type exe_;
exe_setter_(string_type && str) : exe_(std::move(str)) {}
exe_setter_(const string_type & str) : exe_(str) {}
};
template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
template<>
struct char_converter<char, exe_setter_<wchar_t>>
{
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template<>
struct char_converter<wchar_t, exe_setter_<char>>
{
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
{
return {::boost::process::detail::convert(in.exe_)};
}
};
template <typename Char, bool Append >
struct arg_setter_
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
std::vector<string_type> _args;
typedef typename std::vector<string_type>::iterator iterator;
typedef typename std::vector<string_type>::const_iterator const_iterator;
template<typename Iterator>
arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
template<typename Range>
arg_setter_(Range && str) :
_args(std::begin(str),
std::end(str)) {}
iterator begin() {return _args.begin();}
iterator end() {return _args.end();}
const_iterator begin() const {return _args.begin();}
const_iterator end() const {return _args.end();}
arg_setter_(string_type & str) : _args{{str}} {}
arg_setter_(string_type && s) : _args({std::move(s)}) {}
arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_(const value_type* s) : _args({std::move(s)}) {}
template<std::size_t Size>
arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
};
template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
template<>
struct char_converter<char, arg_setter_<wchar_t, true>>
{
static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<wchar_t, arg_setter_<char, true>>
{
static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
{
std::vector<std::wstring> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
template<>
struct char_converter<char, arg_setter_<wchar_t, false>>
{
static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
{
std::vector<std::string> vec(in._args.size());
std::transform(in._args.begin(), in._args.end(), vec.begin(),
[](const std::wstring & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec}; }
};
template<>
struct char_converter<wchar_t, arg_setter_<char, false>>
{
static arg_setter_<wchar_t, false> 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(),
[](const std::string & ws)
{
return ::boost::process::detail::convert(ws);
});
return {vec};
}
};
using api::exe_cmd_init;
template<typename Char>
struct exe_builder
{
//set by path, because that will not be interpreted as a cmd
bool not_cmd = false;
bool shell = false;
using string_type = std::basic_string<Char>;
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())
exe = data.native();
else
args.push_back(data.native());
}
void operator()(const string_type & data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(const Char* data)
{
if (exe.empty())
exe = data;
else
args.push_back(data);
}
void operator()(shell_) {shell = true;}
void operator()(std::vector<string_type> && data)
{
if (data.empty())
return;
auto itr = std::make_move_iterator(data.begin());
auto end = std::make_move_iterator(data.end());
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(const std::vector<string_type> & data)
{
if (data.empty())
return;
auto itr = data.begin();
auto end = data.end();
if (exe.empty())
{
exe = *itr;
itr++;
}
args.insert(args.end(), itr, end);
}
void operator()(exe_setter_<Char> && data)
{
not_cmd = true;
exe = std::move(data.exe_);
}
void operator()(const exe_setter_<Char> & data)
{
not_cmd = true;
exe = data.exe_;
}
void operator()(arg_setter_<Char, false> && data)
{
args.assign(
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(arg_setter_<Char, true> && data)
{
args.insert(args.end(),
std::make_move_iterator(data._args.begin()),
std::make_move_iterator(data._args.end()));
}
void operator()(const arg_setter_<Char, false> & data)
{
args.assign(data._args.begin(), data._args.end());
}
void operator()(const arg_setter_<Char, true> & data)
{
args.insert(args.end(), data._args.begin(), data._args.end());
}
api::exe_cmd_init<Char> get_initializer()
{
if (not_cmd || !args.empty())
{
if (shell)
return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
else
return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
}
else
if (shell)
return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
else
return api::exe_cmd_init<Char>::cmd(std::move(exe));
}
typedef api::exe_cmd_init<Char> result_type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>
{
typedef exe_builder<char> type;
};
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>
{
typedef exe_builder<wchar_t> type;
};
}}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */

View File

@@ -65,8 +65,7 @@ public:
child(child && lhs) noexcept
: _child_handle(std::move(lhs._child_handle)),
_exit_status(std::move(lhs._exit_status)),
_attached (lhs._attached),
_terminated (lhs._terminated)
_attached (lhs._attached)
{
lhs._attached = false;
}
@@ -80,7 +79,6 @@ public:
_child_handle= std::move(lhs._child_handle);
_exit_status = std::move(lhs._exit_status);
_attached = lhs._attached;
_terminated = lhs._terminated;
lhs._attached = false;
return *this;
};
@@ -105,7 +103,7 @@ public:
{
if (valid() && !_exited())
{
int code = -1;
int code;
auto res = boost::process::detail::api::is_running(_child_handle, code);
if (!res && !_exited())
_exit_status->store(code);

View File

@@ -25,13 +25,9 @@
#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/winapi/get_last_error.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#else
#error "System API not supported by boost.process"
#endif
@@ -53,7 +49,7 @@ inline std::error_code get_last_error() noexcept
}
//copied from linux spec.
#if (_XOPEN_SOURCE >= 500 || _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
#if defined (__USE_XOPEN_EXTENDED) && !defined (__USE_XOPEN2K8) || defined( __USE_BSD)
#define BOOST_POSIX_HAS_VFORK 1
#endif
@@ -63,7 +59,7 @@ namespace api = windows;
inline std::error_code get_last_error() noexcept
{
return std::error_code(::boost::winapi::GetLastError(), std::system_category());
return std::error_code(::boost::detail::winapi::GetLastError(), std::system_category());
}
#endif
@@ -72,30 +68,25 @@ inline void throw_last_error(const std::string & msg)
throw process_error(get_last_error(), msg);
}
inline void throw_last_error(const char * msg)
{
throw process_error(get_last_error(), msg);
}
inline void throw_last_error()
{
throw process_error(get_last_error());
}
template<typename Char> constexpr Char null_char();
template<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

@@ -1,75 +1,78 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
//extended handler base.
typedef api::handler_base_ext handler;
template <class Handler>
struct on_setup_ : handler
{
explicit on_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_setup(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_error_ : handler
{
explicit on_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_error(Executor &e, const std::error_code &ec)
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_success_ : handler
{
explicit on_success_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_success(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
}
}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
#include <boost/process/detail/config.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
//extended handler base.
typedef api::handler_base_ext handler;
template <class Handler>
struct on_setup_ : handler
{
explicit on_setup_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_setup(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
template <class Handler>
struct on_error_ : handler
{
explicit on_error_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_error(Executor &e, const std::error_code &ec)
{
handler_(e, ec);
}
private:
Handler handler_;
};
template <class Handler>
struct on_success_ : handler
{
explicit on_success_(Handler handler) : handler_(handler) {}
template <class Executor>
void on_success(Executor &e)
{
handler_(e);
}
private:
Handler handler_;
};
}
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

@@ -20,33 +20,34 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
class io_service;
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class signal_set_service;
template <typename SignalSetService>
class basic_signal_set;
typedef basic_signal_set<signal_set_service> signal_set;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class signal_set;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
template <typename Handler>
class basic_yield_context;
namespace posix {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_descriptor_service;
template <typename StreamDesscriptorService>
class basic_stream_descriptor;
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_descriptor;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
} //posix
} //asio

View File

@@ -1,40 +1,40 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace posix {
struct require_io_context {};
struct async_handler : handler_base_ext, require_io_context
{
};
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_context : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace posix {
struct require_io_service {};
struct async_handler : handler_base_ext, require_io_service
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */

View File

@@ -1,95 +1,94 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
boost::asio::async_write(*pipe, buf,
[pipe, promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&ec, std::size_t size){});
std::move(*pipe).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).source().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(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
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
boost::asio::async_write(*pipe, buf,
[pipe, promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&ec, std::size_t size){});
::close(pipe->native_source());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::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

@@ -1,170 +1,168 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDOUT_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDERR_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
if (::dup2(handle, STDOUT_FILENO) == -1)
return -1;
if (::dup2(handle, STDERR_FILENO) == -1)
return -1;
return 0;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
this->pipe = nullptr;
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
}
template <typename Executor>
void on_exec_setup(Executor &exec)
{
int res = apply_out_handles(pipe->native_sink(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
if (res == -1)
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(pipe->native_sink());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_context
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
{
if (ec && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
std::move(*pipe).sink().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template<typename Executor>
void on_setup(Executor & exec)
{
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(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
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/async_pipe.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace posix {
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDOUT_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
return ::dup2(handle, STDERR_FILENO);
}
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
if (::dup2(handle, STDOUT_FILENO) == -1)
return -1;
if (::dup2(handle, STDERR_FILENO) == -1)
return -1;
return 0;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
this->pipe = nullptr;
::close(pipe->native_sink());
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::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());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
::boost::process::detail::posix::require_io_service
{
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t size)
{
if (ec && (ec.value() != EBADF) && (ec.value() != EPERM) && (ec.value() != ENOENT))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
::close(pipe->native_sink());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::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

@@ -11,7 +11,6 @@
#include <boost/asio/posix/stream_descriptor.hpp>
#include <system_error>
#include <string>
#include <utility>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -20,13 +19,13 @@ 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_context & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink) : _source(ios_source), _sink(ios_sink)
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink) : _source(ios_source), _sink(ios_sink)
{
int fds[2];
if (::pipe(fds) == -1)
@@ -35,11 +34,11 @@ public:
_source.assign(fds[0]);
_sink .assign(fds[1]);
};
inline async_pipe(boost::asio::io_context & ios, const std::string & name)
inline async_pipe(boost::asio::io_service & ios, const std::string & name)
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & io_sink, const std::string & name);
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & io_sink, const std::string & name);
inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
{
@@ -48,15 +47,15 @@ public:
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_context & ios_source,
::boost::asio::io_context & ios_sink,
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
@@ -69,10 +68,10 @@ public:
~async_pipe()
{
if (_sink .native_handle() != -1)
::close(_sink.native_handle());
if (_source.native_handle() != -1)
::close(_source.native_handle());
if (_sink .native() != -1)
::close(_sink.native());
if (_source.native() != -1)
::close(_source.native());
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -109,9 +108,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_context(). post([this]{_sink.close();});
_sink.get_io_service(). post([this]{_sink.close();});
if (_source.is_open())
_source.get_io_context().post([this]{_source.close();});
_source.get_io_service().post([this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -125,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_handle();}
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
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>
@@ -154,35 +154,37 @@ 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_context& ios) &&
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_context& ios) &&
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;
}
handle_type source(::boost::asio::io_context& ios) const &
handle_type source(::boost::asio::io_service& ios) const &
{
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(source_in));
}
handle_type sink (::boost::asio::io_context& ios) const &
handle_type sink (::boost::asio::io_service& ios) const &
{
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
return ::boost::asio::posix::stream_descriptor(ios, ::dup(sink_in));
}
};
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
{
auto fifo = mkfifo(name.c_str(), 0666 );
@@ -206,19 +208,19 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
}
async_pipe::async_pipe(const async_pipe & p) :
_source(const_cast<async_pipe&>(p)._source.get_io_context()),
_sink( const_cast<async_pipe&>(p)._sink.get_io_context())
_source(const_cast<async_pipe&>(p)._source.get_io_service()),
_sink( const_cast<async_pipe&>(p)._sink.get_io_service())
{
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
_source.assign(-1);
else
{
_source.assign(::dup(source_in));
if (_source.native_handle()== -1)
if (_source.native()== -1)
::boost::process::detail::throw_last_error("dup()");
}
@@ -227,7 +229,7 @@ async_pipe::async_pipe(const async_pipe & p) :
else
{
_sink.assign(::dup(sink_in));
if (_sink.native_handle() == -1)
if (_sink.native() == -1)
::boost::process::detail::throw_last_error("dup()");
}
}
@@ -238,8 +240,8 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
source = -1;
else
@@ -265,8 +267,16 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
async_pipe& async_pipe::operator=(async_pipe && lhs)
{
std::swap(_source, lhs._source);
std::swap(_sink, lhs._sink);
if (_source.native_handle() == -1)
::close(_source.native());
if (_sink.native_handle() == -1)
::close(_sink.native());
_source.assign(lhs._source.native_handle());
_sink .assign(lhs._sink .native_handle());
lhs._source.assign(-1);
lhs._sink .assign(-1);
return *this;
}
@@ -277,8 +287,8 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
int sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native_handle();
auto source_in = const_cast<::boost::asio::posix::stream_descriptor &>(_source).native();
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(_sink).native();
if (source_in == -1)
@@ -299,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

@@ -29,13 +29,13 @@ class basic_pipe
int _sink = -1;
public:
explicit basic_pipe(int source, int sink) : _source(source), _sink(sink) {}
explicit basic_pipe(int source, int sink, const std::string&) : _source(source), _sink(sink) {}
explicit basic_pipe(int source, int sink, const std::string & name) : _source(source), _sink(sink) {}
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef int native_handle_type;
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)
@@ -105,10 +100,8 @@ public:
void close()
{
if (_source != -1)
::close(_source);
if (_sink != -1)
::close(_sink);
::close(_source);
::close(_sink);
_source = -1;
_sink = -1;
}

View File

@@ -44,7 +44,7 @@ struct child_handle
return pid;
}
bool in_group() const {return true;}
bool in_group(std::error_code&) const noexcept {return true;}
bool in_group(std::error_code &ec) const noexcept {return true;}
typedef int process_handle_t;
process_handle_t process_handle() const { return pid; }

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

@@ -1,322 +1,325 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
class native_environment_impl
{
static std::vector<std::basic_string<Char>> _load()
{
std::vector<std::basic_string<Char>> val;
auto p = environ;
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
}
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
{
std::vector<Char*> val;
val.resize(vec.size() + 1);
std::transform(vec.begin(), vec.end(), val.begin(),
[](std::basic_string<Char> & str)
{
return &str.front();
});
val.back() = nullptr;
return val;
}
std::vector<std::basic_string<Char>> _buffer = _load();
std::vector<Char*> _impl = _load_var(_buffer);
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload()
{
_buffer = _load();
_impl = _load_var(_buffer);
}
string_type get(const pointer_type id) { return get(string_type(id)); }
void set(const pointer_type id, const pointer_type value)
{
set(string_type(id), string_type(value));
}
void reset(const pointer_type id) { reset(string_type(id)); }
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::detail::throw_last_error();
}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return environ;}
};
template<>
class native_environment_impl<char>
{
public:
using char_type = char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload() {this->_env_impl = ::environ;}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto res = ::setenv(id, value, 1);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::detail::throw_last_error();
reload();
}
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ;
native_handle_type native_handle() const {return ::environ;}
};
template<typename Char>
struct basic_environment_impl
{
std::vector<std::basic_string<Char>> _data {};
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
std::vector<Char*> _env_arr{_load_var(_data)};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = Char**;
void reload()
{
_env_arr = _load_var(_data);
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && ) = default;
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
_env_arr = _load_var(_data);
_env_impl = &*_env_arr.begin();
return *this;
}
basic_environment_impl & operator=(basic_environment_impl && ) = default;
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::detail::convert(st, cv);
}
);
reload();
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.data();
native_handle_type native_handle() const {return &_data.front();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto end = beg;
while (*end != nullptr)
end++;
this->_data.assign(beg, end);
reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr == _data.end())
{
return "";
}
else return
itr->data() + id.size(); //id=Thingy -> +2 points to T
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
*itr = id + equal_sign<Char>() + value;
else
_data.push_back(id + equal_sign<Char>() + value);
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
}
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
{
std::vector<Char*> ret;
ret.reserve(data.size() +1);
for (auto & val : data)
ret.push_back(&val.front());
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ':'; }
template<> constexpr wchar_t env_seperator() {return L':'; }
typedef int native_handle_t;
inline int get_id() {return getpid(); }
inline int native_handle() {return getpid(); }
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_ENVIRONMENT_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <cstdlib>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Char>
class native_environment_impl
{
static std::vector<std::basic_string<Char>> _load()
{
std::vector<std::basic_string<Char>> val;
auto p = environ;
while (*p != nullptr)
{
std::string str = *p;
val.push_back(::boost::process::detail::convert(str));
p++;
}
return val;
}
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & vec)
{
std::vector<Char*> val;
val.resize(vec.size() + 1);
std::transform(vec.begin(), vec.end(), val.begin(),
[](std::basic_string<Char> & str)
{
return &str.front();
});
val.back() = nullptr;
return val;
}
std::vector<std::basic_string<Char>> _buffer = _load();
std::vector<Char*> _impl = _load_var(_buffer);
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload()
{
_buffer = _load();
_impl = _load_var(_buffer);
}
string_type get(const pointer_type id) { return get(string_type(id)); }
void set(const pointer_type id, const pointer_type value)
{
set(string_type(id), string_type(value));
}
void reset(const pointer_type id) { reset(string_type(id)); }
string_type get(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id);
std::string g = ::getenv(id_c.c_str());
return ::boost::process::detail::convert(g.c_str());
}
void set(const string_type & id, const string_type & value)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
std::string value_c = ::boost::process::detail::convert(value.c_str());
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const string_type & id)
{
std::string id_c = ::boost::process::detail::convert(id.c_str());
auto res = ::unsetenv(id_c.c_str());
if (res != 0)
::boost::process::detail::throw_last_error();
}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = _impl.data();
native_handle_type native_handle() const {return environ;}
};
template<>
class native_environment_impl<char>
{
public:
using char_type = char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = char_type **;
void reload() {}
string_type get(const pointer_type id) { return getenv(id); }
void set(const pointer_type id, const pointer_type value)
{
auto val = std::string(id) + "=" + value;
auto res = ::setenv(id, value, true);
if (res != 0)
boost::process::detail::throw_last_error();
}
void reset(const pointer_type id)
{
auto res = ::unsetenv(id);
if (res != 0)
boost::process::detail::throw_last_error();
}
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
native_handle_type _env_impl = environ;
native_handle_type native_handle() const {return environ;}
};
template<typename Char>
struct basic_environment_impl
{
std::vector<std::basic_string<Char>> _data {};
static std::vector<Char*> _load_var(std::vector<std::basic_string<Char>> & data);
std::vector<Char*> _env_arr{_load_var(_data)};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = Char**;
void reload()
{
_env_arr = _load_var(_data);
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && ) = default;
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
_env_arr = _load_var(_data);
_env_impl = &*_env_arr.begin();
return *this;
}
basic_environment_impl & operator=(basic_environment_impl && ) = default;
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(rhs._data.size())
{
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
[&](const std::basic_string<CharR> & st)
{
return ::boost::process::detail::convert(st, cv);
}
);
reload();
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.data();
native_handle_type native_handle() const {return &_data.front();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto end = beg;
while (*end != nullptr)
end++;
this->_data.assign(beg, end);
reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr == _data.end())
{
return "";
}
else return
itr->data() + id.size(); //id=Thingy -> +2 points to T
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
*itr = id + equal_sign<Char>() + value;
}
else
{
_data.push_back(id + equal_sign<Char>() + value);
}
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
auto itr = std::find_if(_data.begin(), _data.end(),
[&](const string_type & st)
{
if (st.size() <= id.size())
return false;
return std::equal(id.begin(), id.end(), st.begin()) && (st[id.size()] == equal_sign<Char>());
}
);
if (itr != _data.end())
{
_data.erase(itr);//and remove it
}
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basic_string<Char>> & data)
{
std::vector<Char*> ret;
ret.reserve(data.size() +1);
for (auto & val : data)
ret.push_back(&val.front());
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ':'; }
template<> constexpr wchar_t env_seperator() {return L':'; }
typedef int native_handle_t;
inline int get_id() {return getpid(); }
inline int native_handle() {return getpid(); }
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */

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);
}
@@ -180,7 +128,7 @@ template<typename Sequence>
class executor
{
template<typename HasHandler, typename UseVFork>
void internal_error_handle(const std::error_code&, const char*, HasHandler, boost::mpl::true_, UseVFork) {}
void internal_error_handle(const std::error_code &ec, const char* msg, HasHandler, boost::mpl::true_, UseVFork) {}
int _pipe_sink = -1;
@@ -233,14 +181,14 @@ class executor
void check_error(boost::mpl::true_) {};
void check_error(boost::mpl::false_)
{
if (_ec)
throw process_error(_ec, _msg);
throw process_error(_ec, _msg);
}
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
inline child invoke(boost::mpl::true_ , boost::mpl::false_ );
@@ -317,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);
@@ -349,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);
@@ -404,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));
@@ -421,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));
@@ -452,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)
{
@@ -467,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));
@@ -485,7 +425,6 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
return child();
}
_ec.clear();
this->pid = ::vfork();
if (pid == -1)
{
@@ -500,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));
@@ -512,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

@@ -1,76 +1,76 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
explicit file_descriptor(const char* path, mode_t mode = read_write)
: _handle(create_file(path, mode))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != -1)
::close(_handle);
}
int handle() const { return _handle;}
private:
static int create_file(const char* name, mode_t mode )
{
switch(mode)
{
case read:
return ::open(name, O_RDONLY);
case write:
return ::open(name, O_WRONLY | O_CREAT, 0660);
case read_write:
return ::open(name, O_RDWR | O_CREAT, 0660);
default:
return -1;
}
}
int _handle = -1;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_FILE_DESCRIPTOR_HPP_
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
explicit file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
explicit file_descriptor(const char* path, mode_t mode = read_write)
: _handle(create_file(path, mode))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != -1)
::close(_handle);
}
int handle() const { return _handle;}
private:
static int create_file(const char* name, mode_t mode )
{
switch(mode)
{
case read:
return ::open(name, O_RDONLY);
case write:
return ::open(name, O_WRONLY | O_CREAT, 0660);
case read_write:
return ::open(name, O_RDWR | O_CREAT, 0660);
default:
return -1;
}
}
int _handle = -1;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */

View File

@@ -1,40 +1,40 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
template <class WindowsExecutor>
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <cstdio>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct file_in : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t)) {}
file_in(FILE * f) : handle(fileno(f)) {}
template <class WindowsExecutor>
void on_exec_setup(WindowsExecutor &e) const
{
if (::dup2(handle, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif

View File

@@ -1,65 +1,65 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct file_out : handler_base_ext
{
file_descriptor file;
int handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write), handle(file.handle()) {}
file_out(FILE * f) : handle(fileno(f)) {}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void file_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void file_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(handle, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(handle, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif

View File

@@ -28,7 +28,7 @@ struct group_ref : handler_base_ext
{}
template <class Executor>
void on_exec_setup(Executor&) const
void on_exec_setup(Executor& exec) const
{
if (grp.grp == -1)
::setpgid(0, 0);

View File

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

View File

@@ -1,114 +0,0 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_context.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 <boost/process/detail/posix/sigchld_service.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <vector>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
};
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_context_ref : handler_base_ext
{
io_context_ref(boost::asio::io_context & ios) : ios(ios)
{
}
boost::asio::io_context &get() {return ios;};
template <class Executor>
void on_success(Executor& exec)
{
//must be on the heap so I can move it into the lambda.
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
return;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
auto & es = exec.exit_status;
auto wh = [funcs, es](int val, const std::error_code & ec)
{
es->store(val);
for (auto & func : funcs)
func(WEXITSTATUS(val), ec);
};
sigchld_service.async_wait(exec.pid, std::move(wh));
}
private:
boost::asio::io_context &ios;
boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios);
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */

View File

@@ -0,0 +1,162 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_POSIX_IO_SERVICE_REF_HPP_
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <vector>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
};
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_service_ref : handler_base_ext
{
io_service_ref(boost::asio::io_service & ios) : ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
template <class Executor>
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);
auto signal_p = wh.signal_.get();
signal_p->async_wait(std::move(wh));
}
struct wait_handler
{
std::shared_ptr<boost::asio::signal_set> signal_;
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = default;
wait_handler(wait_handler && ) = default;
wait_handler(
std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & ios,
const std::shared_ptr<std::atomic<int>> &exit_status)
: signal_(new boost::asio::signal_set(ios, SIGCHLD)),
funcs(std::move(funcs)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in, int /*signal*/)
{
int status;
::wait(&status);
std::error_code ec(ec_in.value(), std::system_category());
int val = WEXITSTATUS(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

@@ -1,35 +1,35 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext
{
file_descriptor source{"/dev/null", file_descriptor::read};
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct null_in : handler_base_ext
{
file_descriptor source{"/dev/null", file_descriptor::read};
public:
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source.handle(), STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
};
}}}}
#endif

View File

@@ -1,58 +1,58 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_POSIX_PIPE_OUT_HPP
#include <boost/process/detail/posix/handler.hpp>
#include <boost/process/detail/posix/file_descriptor.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct null_out : handler_base_ext
{
file_descriptor sink{"/dev/null", file_descriptor::write};
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void null_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
template<>
template<typename Executor>
void null_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink.handle(), STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink.handle(), STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
}
}}}}
#endif

View File

@@ -1,35 +1,35 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
return handler;
};
};
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
{
return handler;
};
};
}}}}
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */

View File

@@ -1,90 +1,51 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
{
int source;
int sink; //opposite end
pipe_in(int sink, int source) : source(source), sink(sink) {}
template<typename T>
pipe_in(T & p) : source(p.native_source()), sink(p.native_sink())
{
p.assign_source(-1);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(source);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(source);
}
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(source, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(source);
::close(sink);
}
};
class async_pipe;
struct async_pipe_in : public pipe_in
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_in(AsyncPipe & p) : pipe_in(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).source().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_POSIX_PIPE_IN_HPP
#define BOOST_PROCESS_POSIX_PIPE_IN_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
struct pipe_in : handler_base_ext
{
int descr_;
template<typename T>
pipe_in(const T & p) : descr_(p.native_source()) {}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(descr_);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(descr_);
}
template <class Executor>
void on_exec_setup(Executor &e) const
{
if (::dup2(descr_, STDIN_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(descr_);
}
};
}}}}
#endif

View File

@@ -1,116 +1,76 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int sink;
int source; //opposite end
pipe_out(int sink, int source) : sink(sink), source(source) {}
template<typename T>
pipe_out(T & p) : sink(p.native_sink()), source(p.native_source())
{
p.assign_sink(-1);
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(sink);
}
template<typename Executor>
void on_success(Executor &) const
{
::close(sink);
}
template <typename Executor>
void on_exec_setup(Executor &e) const;
};
template<>
template<typename Executor>
void pipe_out<1,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(sink, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(sink, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(sink);
::close(source);
}
class async_pipe;
template<int p1, int p2>
struct async_pipe_out : public pipe_out<p1, p2>
{
async_pipe &pipe;
template<typename AsyncPipe>
async_pipe_out(AsyncPipe & p) : pipe_out<p1, p2>(p.native_sink(), p.native_source()), pipe(p)
{
}
template<typename Pipe, typename Executor>
static void close(Pipe & pipe, Executor &)
{
boost::system::error_code ec;
std::move(pipe).sink().close(ec);
}
template<typename Executor>
void on_error(Executor & exec, const std::error_code &)
{
close(pipe, exec);
}
template<typename Executor>
void on_success(Executor &exec)
{
close(pipe, exec);
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#define BOOST_PROCESS_DETAIL_POSIX_PIPE_OUT_HPP
#include <boost/process/pipe.hpp>
#include <boost/process/detail/posix/handler.hpp>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
template<int p1, int p2>
struct pipe_out : handler_base_ext
{
int descr_;
template<typename T>
pipe_out(const T & p) : descr_(p.native_sink()) {}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::close(descr_);
}
template<typename Executor>
void on_success(Executor &) const
{
::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(descr_, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup3() failed");
::close(descr_);
}
template<>
template<typename Executor>
void pipe_out<2,-1>::on_exec_setup(Executor &e) const
{
if (::dup2(descr_, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(descr_);
}
template<>
template<typename Executor>
void pipe_out<1,2>::on_exec_setup(Executor &e) const
{
if (::dup2(descr_, STDOUT_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
if (::dup2(descr_, STDERR_FILENO) == -1)
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
::close(descr_);
}
}}}}
#endif

View File

@@ -24,6 +24,7 @@ inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
{
std::string result;
for (const boost::filesystem::path & pp : path)
{
auto p = pp / filename;

View File

@@ -1,113 +0,0 @@
// Copyright (c) 2017 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_SIGCHLD_SERVICE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <signal.h>
#include <functional>
#include <sys/wait.h>
namespace boost { namespace process { namespace detail { namespace posix {
class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
{
boost::asio::io_context::strand _strand{get_io_context()};
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
public:
sigchld_service(boost::asio::io_context & io_context)
: boost::asio::detail::service_base<sigchld_service>(io_context)
{
}
template <typename SignalHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler,
void (int, std::error_code))
async_wait(::pid_t pid, SignalHandler && handler)
{
boost::asio::async_completion<
SignalHandler, void(boost::system::error_code)> init{handler};
auto & h = init.completion_handler;
_strand.post(
[this, pid, h]
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code & ec, int)
{
_strand.post([this,ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
});
return init.result.get();
}
void shutdown_service() override
{
_receivers.clear();
}
void cancel()
{
_signal_set.cancel();
}
void cancel(boost::system::error_code & ec)
{
_signal_set.cancel(ec);
}
};
void sigchld_service::_handle_signal(const boost::system::error_code & ec)
{
std::error_code ec_{ec.value(), std::system_category()};
if (ec_)
{
for (auto & r : _receivers)
r.second(-1, ec_);
return;
}
int status;
int pid = ::waitpid(0, &status, WNOHANG);
auto itr = std::find_if(_receivers.begin(), _receivers.end(),
[&pid](const std::pair<::pid_t, std::function<void(int, std::error_code)>> & p)
{
return p.first == pid;
});
if (itr != _receivers.cend())
{
_strand.get_io_context().wrap(itr->second)(status, ec_);
_receivers.erase(itr);
}
if (!_receivers.empty())
{
_signal_set.async_wait(
[this](const boost::system::error_code & ec, int)
{
_strand.post([ec]{});
this->_handle_signal(ec);
});
}
}
}
}
}
}
#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,155 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_POSIX_TUPLE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_TUPLE_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <boost/fusion/tuple.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
template<typename Executor>
struct tuple_on_setup
{
Executor & exec;
template<typename T>
void operator()(T *p)
{
p->on_setup(exec);
}
};
template<typename Executor>
struct tuple_on_error
{
Executor & exec;
const std::error_code & ec;
template<typename T>
void operator()(T *p)
{
p->on_setup(exec);
}
};
template<typename Executor>
struct tuple_on_success
{
Executor & exec;
template<typename T>
void operator()(T *p)
{
p->on_setup(exec);
}
};
template<typename Executor>
struct tuple_on_fork_error
{
Executor & exec;
const std::error_code &ec;
template<typename T>
void operator()(T *t)
{
t->on_fork_error(exec, ec);
}
};
template<typename Executor>
struct tuple_on_exec_setup
{
Executor & exec;
template<typename T>
void operator()(T *t)
{
t->on_exec_setup(exec);
}
};
template<typename Executor>
struct tuple_on_exec_error
{
Executor & exec;
const std::error_code &ec;
template<typename T>
void operator()(T *t)
{
t->on_exec_error(exec, ec);
}
};
template<typename ...Args>
struct initializer_tuple : Args...
{
template <class Executor>
void on_setup(Executor& exec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_setup<Executor> func{exec};
boost::fusion::for_each(tup, func);
}
template <class Executor>
void on_error(Executor& exec, const std::error_code & ec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_setup<Executor> func{exec};
boost::fusion::for_each(tup, func);
}
template <class Executor>
void on_success(Executor& exec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_setup<Executor> func{exec};
boost::fusion::for_each(tup, func);
}
template<typename Executor>
void on_fork_error (Executor & exec, const std::error_code& ec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_fork_error<Executor> func{exec, ec};
boost::fusion::for_each(tup, func);
}
template<typename Executor>
void on_exec_setup (Executor & exec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_exec_setup<Executor> func{exec};
boost::fusion::for_each(tup, func);
}
template<typename Executor>
void on_exec_error (Executor & exec, const std::error_code& ec)
{
auto tup = boost::fusion::make_tuple(static_cast<Args*>(this)...);
tuple_on_exec_error<Executor> func{exec, ec};
boost::fusion::for_each(tup, func);
}
};
}
}
}
}
#endif

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

@@ -15,7 +15,7 @@
#include <system_error>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -26,11 +26,9 @@ inline void wait(const child_handle &p, int & exit_code)
do
{
ret = ::waitpid(p.pid, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process terminated due to receipt of a signal");
exit_code = status;
}
@@ -43,7 +41,7 @@ inline void wait(const child_handle &p, int & exit_code, std::error_code &ec) no
{
ret = ::waitpid(p.pid, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
@@ -69,27 +67,26 @@ inline bool wait_for(
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
time_out_occured = true;
break;
}
}
while ((ret == 0) ||
((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return true;
return !time_out_occured;
}
@@ -106,26 +103,21 @@ inline bool wait_for(
auto start = std::chrono::system_clock::now();
auto time_out = start + rel_time;
bool timed_out;
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
time_out_occured = true;
break;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (timed_out && (ret == -1))
return false;
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
@@ -134,80 +126,73 @@ inline bool wait_for(
exit_code = status;
}
return true;
return !time_out_occured;
}
template< class Clock, class Duration >
template< class Rep, class Period >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& time_out)
const std::chrono::duration<Rep, Period>& time_out)
{
pid_t ret;
int status;
bool timed_out;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
time_out_occured = true;
break;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (timed_out && !WIFEXITED(status))
return false;
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
exit_code = status;
return true;
return !time_out_occured;
}
template< class Clock, class Duration >
template< class Rep, class Period >
inline bool wait_until(
const child_handle &p,
int & exit_code,
const std::chrono::time_point<Clock, Duration>& time_out,
const std::chrono::duration<Rep, Period>& time_out,
std::error_code & ec) noexcept
{
pid_t ret;
int status;
bool timed_out;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
ret = ::waitpid(p.pid, &status, WNOHANG);
if (ret == 0)
ret = ::waitpid(p.pid, &status, WUNTRACED | WNOHANG);
if (std::chrono::system_clock::now() >= time_out)
{
timed_out = std::chrono::system_clock::now() >= time_out;
if (timed_out)
return false;
time_out_occured = true;
break;
}
}
while ((ret == 0) ||
(((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status))));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (timed_out && !WIFEXITED(status))
return false;
if (ret == -1)
ec = boost::process::detail::get_last_error();
else
@@ -216,7 +201,7 @@ inline bool wait_until(
exit_code = status;
}
return true;
return !time_out_occured;
}
}}}}

View File

@@ -25,11 +25,9 @@ inline void wait(const group_handle &p)
do
{
ret = ::waitpid(-p.grp, &status, 0);
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
} while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
}
inline void wait(const group_handle &p, std::error_code &ec) noexcept
@@ -41,12 +39,10 @@ inline void wait(const group_handle &p, std::error_code &ec) noexcept
{
ret = ::waitpid(-p.grp, &status, 0);
}
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && (errno == EINTR)) || (ret != -1 && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();
@@ -74,14 +70,13 @@ inline bool wait_for(
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
return !time_out_occured;
}
@@ -110,14 +105,12 @@ inline bool wait_for(
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();
@@ -135,6 +128,8 @@ inline bool wait_until(
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
@@ -145,14 +140,12 @@ inline bool wait_until(
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
boost::process::detail::throw_last_error("waitpid(2) failed");
if (WIFSIGNALED(status))
throw process_error(std::error_code(), "process group terminated due to receipt of a signal");
return !time_out_occured;
@@ -169,6 +162,8 @@ inline bool wait_until(
pid_t ret;
int status;
auto start = std::chrono::system_clock::now();
bool time_out_occured = false;
do
{
@@ -179,14 +174,12 @@ inline bool wait_until(
break;
}
}
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status) && !WIFSIGNALED(status)));
while (((ret == -1) && errno == EINTR) ||
((ret != -1) && !WIFEXITED(status)));
if (ret == -1)
ec = boost::process::detail::get_last_error();
else if (WIFSIGNALED(status))
ec = std::make_error_code(std::errc::no_such_process);
else
ec.clear();

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

@@ -1,17 +1,17 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_TRAITS_HPP_
#define BOOST_PROCESS_TRAITS_HPP_
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/async.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
#include <boost/process/detail/traits/error.hpp>
#include <boost/process/detail/traits/wchar_t.hpp>
#endif /* BOOST_PROCESS_TRAITS_HPP_ */

View File

@@ -1,34 +1,34 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace asio {
class io_context;
}}
namespace boost { namespace process { namespace detail {
struct async_tag {};
template<>
struct initializer_builder<async_tag>;
template<> struct initializer_tag<::boost::asio::io_context> { typedef async_tag type;};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ASYNC_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace asio {
class io_service;
}}
namespace boost { namespace process { namespace detail {
struct async_tag {};
template<>
struct initializer_builder<async_tag>;
template<> struct initializer_tag<::boost::asio::io_service> { typedef async_tag type;};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -1,85 +1,82 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#include <string>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct cmd_or_exe_tag {};
struct shell_;
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<const char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
};
template <typename Char>
struct exe_setter_;
template <typename Char, bool Append = false>
struct arg_setter_;
template <typename Char, bool Append>
struct initializer_tag<arg_setter_<Char, Append>> { typedef cmd_or_exe_tag<Char> type;};
template<typename Char> struct initializer_tag<exe_setter_<Char>> { typedef cmd_or_exe_tag<Char> type;};
template<>
struct initializer_builder<cmd_or_exe_tag<char>>;
template<>
struct initializer_builder<cmd_or_exe_tag<wchar_t>>;
}}}
#endif /* BOOST_PROCESS_DETAIL_STRING_TRAITS_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_CMD_OR_EXE_HPP_
#include <string>
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
template<typename Char>
struct cmd_or_exe_tag {};
struct shell_;
template<> struct initializer_tag<const char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<const wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<char* > { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<wchar_t* > { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char [Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t [Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<std::size_t Size> struct initializer_tag<const char (&)[Size]> { typedef cmd_or_exe_tag<char> type;};
template<std::size_t Size> struct initializer_tag<const wchar_t (&)[Size]> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::basic_string<char >> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::basic_string<wchar_t >> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<char >>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<std::basic_string<wchar_t >>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::vector<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::vector<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<std::initializer_list<char *>> { typedef cmd_or_exe_tag<char> type;};
template<> struct initializer_tag<std::initializer_list<wchar_t *>> { typedef cmd_or_exe_tag<wchar_t> type;};
template<> struct initializer_tag<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

@@ -1,76 +1,80 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
template<typename T>
struct is_initializer : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
template<typename T>
struct initializer_tag;// { typedef void type; };
//remove const
template<typename T>
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
//remove &
template<typename T>
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
//remove const &
template<typename T>
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
template<typename T>
struct initializer_builder;
template<typename First, typename ...Args>
struct valid_argument_list;
template<typename First>
struct valid_argument_list<First>
{
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First, typename ...Args>
struct valid_argument_list
{
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
typedef std::integral_constant<bool, value> type;
};
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <boost/none.hpp>
#include <type_traits>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif
namespace boost { namespace process { namespace detail {
template<typename T>
struct is_initializer : std::is_base_of<handler_base, T> {};
template<typename T>
struct is_initializer<T&> : std::is_base_of<handler_base, T> {};
template<typename T>
struct initializer_tag;// { typedef void type; };
//remove const
template<typename T>
struct initializer_tag<const T> { typedef typename initializer_tag<T>::type type; };
//remove &
template<typename T>
struct initializer_tag<T&> { typedef typename initializer_tag<T>::type type; };
//remove const &
template<typename T>
struct initializer_tag<const T&> { typedef typename initializer_tag<T>::type type; };
template<typename T>
struct initializer_builder;
template<typename First, typename ...Args>
struct valid_argument_list;
template<typename First>
struct valid_argument_list<First>
{
constexpr static bool value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
typedef std::integral_constant<bool, value> type;
};
template<typename First, typename ...Args>
struct valid_argument_list
{
constexpr static bool my_value = is_initializer<First>::value || !std::is_void<typename initializer_tag<First>::type>::value;
constexpr static bool value = valid_argument_list<Args...>::value && my_value;
typedef std::integral_constant<bool, value> type;
};
struct error_tag;
template<>
struct initializer_tag<std::error_code>;
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */

View File

@@ -1,53 +1,53 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
template<typename Char>
class basic_environment;
template<typename Char>
class basic_native_environment;
namespace detail {
template<typename Char>
struct env_tag {};
template<typename Char> struct env_set;
template<typename Char> struct env_append;
template<typename Char> struct env_reset;
template<typename Char> struct env_init;
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
}
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ENV_HPP_
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process {
template<typename Char>
class basic_environment;
template<typename Char>
class basic_native_environment;
namespace detail {
template<typename Char>
struct env_tag {};
template<typename Char> struct env_set;
template<typename Char> struct env_append;
template<typename Char> struct env_reset;
template<typename Char> struct env_init;
template<typename Char> struct initializer_tag<env_set<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_append<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<env_reset<Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<env_init <Char>> { typedef env_tag<Char> type;};
template<typename Char> struct initializer_tag<::boost::process::basic_environment<Char>> { typedef env_tag<Char> type; };
template<typename Char> struct initializer_tag<::boost::process::basic_native_environment<Char>> { typedef env_tag<Char> type; };
template<> struct initializer_builder<env_tag<char>>;
template<> struct initializer_builder<env_tag<wchar_t>>;
}
}}
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */

View File

@@ -1,27 +1,33 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_ERROR_HPP_
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
struct error_tag;
template<>
struct initializer_tag<std::error_code>;
}}}
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_DECL_HPP_
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
struct error_tag {};
template<>
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

@@ -19,35 +19,27 @@ template<typename Allocator>
class basic_streambuf;
typedef basic_streambuf<std::allocator<char>> streambuf;
class io_context;
class io_service;
template <typename Handler>
class basic_yield_context;
namespace windows {
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class stream_handle_service;
template <typename StreamHandleService>
class basic_stream_handle;
typedef basic_stream_handle<stream_handle_service> stream_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class stream_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
class object_handle_service;
template <typename ObjectHandleService>
class basic_object_handle;
typedef basic_object_handle<object_handle_service> object_handle;
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
class object_handle;
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
} //windows
} //asio

View File

@@ -1,40 +1,40 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace windows {
struct require_io_context {};
struct async_handler : handler_base_ext, require_io_context
{
};
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_context : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_context<T&> : std::is_base_of<require_io_context, T> {};
template<typename T>
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#define BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <type_traits>
namespace boost { namespace process { namespace detail { namespace windows {
struct require_io_service {};
struct async_handler : handler_base_ext, require_io_service
{
};
template<typename T>
struct is_async_handler : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct is_async_handler<const T&> : std::is_base_of<async_handler, T> {};
template<typename T>
struct does_require_io_service : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<T&> : std::is_base_of<require_io_service, T> {};
template<typename T>
struct does_require_io_service<const T&> : std::is_base_of<require_io_service, T> {};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */

View File

@@ -1,105 +1,105 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
if (this->promise)
{
auto promise = this->promise;
boost::asio::async_write(*pipe, buf,
[promise](const boost::system::error_code & ec, std::size_t)
{
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).source().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::boost::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_context(exec.seq));
::boost::winapi::HANDLE_ source_handle = std::move(*pipe).source().native_handle();
boost::winapi::SetHandleInformation(source_handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
exec.startup_info.hStdInput = source_handle;
exec.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
exec.inherit_handles = true;
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/asio/write.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Buffer>
struct async_in_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
std::shared_ptr<std::promise<void>> promise;
async_in_buffer operator>(std::future<void> & fut)
{
promise = std::make_shared<std::promise<void>>();
fut = promise->get_future(); return std::move(*this);
}
std::shared_ptr<boost::process::async_pipe> pipe;
async_in_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &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)
{
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
promise->set_value();
});
}
else
boost::asio::async_write(*pipe, buf,
[pipe](const boost::system::error_code&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

@@ -1,179 +1,176 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/asio_fwd.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::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::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::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::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::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::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_context
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t){});
std::move(*pipe).sink().close();
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_context
{
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor&)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
std::move(*pipe).sink().close();
boost::asio::async_read(*pipe, *buffer,
[pipe, buffer, promise](const boost::system::error_code& ec, std::size_t)
{
if (ec && (ec.value() != ::boost::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
if (buffer->size() > 0)
{
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
}
promise->set_value(std::move(arg));
}
});
this->pipe = nullptr;
this->buffer = nullptr;
this->promise = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
std::move(*pipe).sink().close();
}
template <typename WindowsExecutor>
void on_setup(WindowsExecutor &exec)
{
if (!pipe)
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
apply_out_handles(exec, std::move(*pipe).sink().native_handle(),
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_ASYNC_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/asio/read.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/asio_fwd.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <istream>
#include <memory>
#include <exception>
#include <future>
namespace boost { namespace process { namespace detail { namespace windows {
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 2>, std::integral_constant<int, -1>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template <typename Executor>
inline void apply_out_handles(Executor &e, void* handle, std::integral_constant<int, 1>, std::integral_constant<int, 2>)
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<int p1, int p2, typename Buffer>
struct async_out_buffer : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
Buffer & buf;
std::shared_ptr<boost::process::async_pipe> pipe;
async_out_buffer(Buffer & buf) : buf(buf)
{
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
boost::asio::async_read(*pipe, buf,
[pipe](const boost::system::error_code&, std::size_t size){});
::boost::detail::winapi::CloseHandle(pipe->native_sink());
this->pipe = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::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>());
}
};
template<int p1, int p2, typename Type>
struct async_out_future : ::boost::process::detail::windows::handler_base_ext,
::boost::process::detail::windows::require_io_service
{
std::shared_ptr<boost::process::async_pipe> pipe;
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
async_out_future(std::future<Type> & fut)
{
fut = promise->get_future();
}
template <typename Executor>
inline void on_success(Executor &exec)
{
auto pipe = this->pipe;
auto buffer = this->buffer;
auto promise = this->promise;
::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 size)
{
if (ec && (ec.value() != ::boost::detail::winapi::ERROR_BROKEN_PIPE_))
{
std::error_code e(ec.value(), std::system_category());
promise->set_exception(std::make_exception_ptr(process_error(e)));
}
else
{
std::istream is (buffer.get());
Type arg;
arg.resize(buffer->size());
is.read(&*arg.begin(), buffer->size());
promise->set_value(std::move(arg));
}
});
this->pipe = nullptr;
this->buffer = nullptr;
this->promise = nullptr;
}
template<typename Executor>
void on_error(Executor &, const std::error_code &) const
{
::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

@@ -6,16 +6,15 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ASYNC_PIPE_HPP_
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/pipes.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/basic_pipe.hpp>
#include <boost/asio/windows/stream_handle.hpp>
#include <atomic>
#include <system_error>
#include <string>
@@ -25,9 +24,9 @@ inline std::string make_pipe_name()
{
std::string name = "\\\\.\\pipe\\boost_process_auto_pipe_";
auto pid = ::boost::winapi::GetCurrentProcessId();
auto pid = ::boost::detail::winapi::GetCurrentProcessId();
static std::atomic_size_t cnt = 0;
static unsigned long long cnt = 0;
name += std::to_string(pid);
name += "_";
name += std::to_string(cnt++);
@@ -40,33 +39,33 @@ class async_pipe
::boost::asio::windows::stream_handle _source;
::boost::asio::windows::stream_handle _sink ;
public:
typedef ::boost::winapi::HANDLE_ native_handle_type;
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
typedef ::boost::asio::windows::stream_handle handle_type;
inline async_pipe(boost::asio::io_context & ios,
inline async_pipe(boost::asio::io_service & ios,
const std::string & name = make_pipe_name())
: async_pipe(ios, ios, name) {}
inline async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
inline async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name = make_pipe_name());
inline async_pipe(const async_pipe& rhs);
async_pipe(async_pipe&& rhs) : _source(std::move(rhs._source)), _sink(std::move(rhs._sink))
{
rhs._source.assign (::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign (::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._source.assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign (::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(::boost::asio::io_context & ios_source,
::boost::asio::io_context & ios_sink,
explicit async_pipe(::boost::asio::io_service & ios_source,
::boost::asio::io_service & ios_sink,
const basic_pipe<CharT, Traits> & p)
: _source(ios_source, p.native_source()), _sink(ios_sink, p.native_sink())
{
}
template<class CharT, class Traits = std::char_traits<CharT>>
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p)
explicit async_pipe(boost::asio::io_service & ios, const basic_pipe<CharT, Traits> & p)
: async_pipe(ios, ios, p)
{
}
@@ -79,8 +78,10 @@ public:
~async_pipe()
{
boost::system::error_code ec;
close(ec);
if (_sink .native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
if (_source.native() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
}
template<class CharT, class Traits = std::char_traits<CharT>>
@@ -99,26 +100,20 @@ public:
if (_sink.is_open())
{
_sink.close();
_sink = handle_type(_sink.get_io_context());
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
if (_source.is_open())
{
_source.close();
_source = handle_type(_source.get_io_context());
_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_context());
}
if (_source.is_open())
{
_source.close(ec);
_source = handle_type(_source.get_io_context());
}
}
bool is_open() const
@@ -128,9 +123,9 @@ public:
void async_close()
{
if (_sink.is_open())
_sink.get_io_context(). post([this]{_sink.close();});
_sink.get_io_service(). post([this]{_sink.close();});
if (_source.is_open())
_source.get_io_context().post([this]{_source.close();});
_source.get_io_service().post([this]{_source.close();});
}
template<typename MutableBufferSequence>
@@ -144,8 +139,8 @@ public:
return _sink.write_some(buffers);
}
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native_handle();}
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native_handle();}
native_handle_type native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
native_handle_type native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
template<typename MutableBufferSequence,
typename ReadHandler>
@@ -175,47 +170,47 @@ public:
handle_type && source() && { return std::move(_source); }
handle_type && sink() && { return std::move(_sink); }
handle_type source(::boost::asio::io_context& ios) &&
handle_type source(::boost::asio::io_service& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _source.native_handle());
_source.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
_source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return stolen;
}
handle_type sink (::boost::asio::io_context& ios) &&
handle_type sink (::boost::asio::io_service& ios) &&
{
::boost::asio::windows::stream_handle stolen(ios, _sink.native_handle());
_sink.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
_sink.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return stolen;
}
handle_type source(::boost::asio::io_context& ios) const &
handle_type source(::boost::asio::io_service& ios) const &
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
auto source_in = const_cast<handle_type&>(_source).native_handle();
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
::boost::detail::winapi::HANDLE_ source;
auto source_in = const_cast<handle_type&>(_source).native();
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, source);
}
handle_type sink (::boost::asio::io_context& ios) const &
handle_type sink (::boost::asio::io_service& ios) const &
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ sink;
auto sink_in = const_cast<handle_type&>(_sink).native_handle();
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
::boost::detail::winapi::HANDLE_ sink;
auto sink_in = const_cast<handle_type&>(_sink).native();
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return ::boost::asio::windows::stream_handle(ios, sink);
@@ -225,32 +220,32 @@ public:
async_pipe::async_pipe(const async_pipe& p) :
_source(const_cast<handle_type&>(p._source).get_io_context()),
_sink (const_cast<handle_type&>(p._sink).get_io_context())
_source(const_cast<handle_type&>(p._source).get_io_service()),
_sink (const_cast<handle_type&>(p._sink).get_io_service())
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<handle_type&>(p._source).native_handle();
auto sink_in = const_cast<handle_type&>(p._sink).native_handle();
auto source_in = const_cast<handle_type&>(p._source).native();
auto sink_in = const_cast<handle_type&>(p._sink).native();
if (source_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (source_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in, proc, &source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (sink_in == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in, proc, &sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
_source.assign(source);
@@ -258,32 +253,32 @@ async_pipe::async_pipe(const async_pipe& p) :
}
async_pipe::async_pipe(boost::asio::io_context & ios_source,
boost::asio::io_context & ios_sink,
async_pipe::async_pipe(boost::asio::io_service & ios_source,
boost::asio::io_service & ios_sink,
const std::string & name) : _source(ios_source), _sink(ios_sink)
{
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
name.c_str(),
::boost::winapi::PIPE_ACCESS_INBOUND_
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe(" + name + ") failed");
_source.assign(source);
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
name.c_str(),
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::winapi::OPEN_EXISTING_,
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::detail::winapi::OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_sink.assign(sink);
@@ -291,82 +286,82 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
async_pipe& async_pipe::operator=(const async_pipe & p)
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto &source_in = const_cast<::boost::asio::windows::stream_handle &>(p._source);
auto &sink_in = const_cast<::boost::asio::windows::stream_handle &>(p._sink);
if (source_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, source_in.native_handle(), proc, &source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
if (source_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, source_in.native(), proc, &source, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in.native_handle() == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
proc, sink_in.native_handle(), proc, &sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
if (sink_in.native() == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, sink_in.native(), proc, &sink, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
//so we also assign the io_context
_source = ::boost::asio::windows::stream_handle(source_in.get_io_context(), source);
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_context(), sink);
//so we also assign the io_service
_source = ::boost::asio::windows::stream_handle(source_in.get_io_service(), source);
_sink = ::boost::asio::windows::stream_handle(source_in.get_io_service(), sink);
return *this;
}
async_pipe& async_pipe::operator=(async_pipe && rhs)
{
if (_source.native_handle() != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source.native_handle());
if (_source.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source.native());
if (_sink.native_handle() != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink.native_handle());
if (_sink.native_handle() != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink.native());
_source.assign(rhs._source.native_handle());
_sink .assign(rhs._sink .native_handle());
rhs._source.assign(::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign(::boost::winapi::INVALID_HANDLE_VALUE_);
rhs._source.assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
rhs._sink .assign(::boost::detail::winapi::INVALID_HANDLE_VALUE_);
return *this;
}
template<class CharT, class Traits>
async_pipe::operator basic_pipe<CharT, Traits>() const
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
::boost::winapi::HANDLE_ source;
::boost::winapi::HANDLE_ sink;
::boost::detail::winapi::HANDLE_ source;
::boost::detail::winapi::HANDLE_ sink;
//cannot get the handle from a const object.
auto source_in = const_cast<::boost::asio::windows::stream_handle &>(_source).native_handle();
auto sink_in = const_cast<::boost::asio::windows::stream_handle &>(_sink).native_handle();
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::winapi::INVALID_HANDLE_VALUE_)
source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
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::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (sink_in == ::boost::winapi::INVALID_HANDLE_VALUE_)
sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
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::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
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

@@ -1,178 +1,164 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <vector>
#include <string>
#include <iterator>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
//put in quotes if it has spaces
{
boost::replace_all(st, "\"", "\\\"");
auto it = std::find(st.begin(), st.end(), ' ');
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), '"');
st += '"';
}
}
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"');
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
}
return st;
}
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
{
std::wstring st = exe;
//put in quotes if it has spaces
{
boost::replace_all(st, L"\"", L"\\\"");
auto it = std::find(st.begin(), st.end(), L' ');
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), L'"');
st += L'"';
}
}
for (auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
auto it = std::find(arg.begin(), arg.end(), L' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += L' ';
st += arg;
}
return st;
}
template<typename Char>
struct exe_cmd_init : handler_base_ext
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
static const char* c_arg(char) { return "/c";}
static const wchar_t* c_arg(wchar_t) { return L"/c";}
exe_cmd_init(const string_type & exe, bool cmd_only = false)
: exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, bool cmd_only = false)
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
template <class Executor>
void on_setup(Executor& exec) const
{
if (cmd_only && args.empty())
exec.cmd_line = exe.c_str();
else
{
exec.exe = exe.c_str();
exec.cmd_line = args.c_str();
}
}
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
{
return exe_cmd_init<Char>(std::move(exe), std::move(args));
}
static exe_cmd_init<Char> cmd(string_type&& cmd)
{
return exe_cmd_init<Char>(std::move(cmd), true);
}
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(
std::move(sh),
std::move(args));
}
private:
string_type exe;
string_type args;
bool cmd_only;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_BASIC_CMD_HPP_
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/process/shell.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <vector>
#include <string>
#include <iterator>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
inline std::string build_args(const std::string & exe, std::vector<std::string> && data)
{
std::string st = exe;
//put in quotes if it has spaces
{
boost::replace_all(st, "\"", "\\\"");
auto it = std::find(st.begin(), st.end(), ' ');
if (it != st.end())//contains spaces.
{
st.insert(st.begin(), '"');
st += '"';
}
}
for (auto & arg : data)
{
boost::replace_all(arg, "\"", "\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"');
arg += '"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += ' ';
st += arg;
}
return st;
}
inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstring> && data)
{
std::wstring st = exe;
for (auto & arg : data)
{
boost::replace_all(arg, L"\"", L"\\\"");
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
if (it != arg.end())//ok, contains spaces.
{
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), L'"');
arg += L'"'; //thats the post one.
}
if (!st.empty())//first one does not need a preceeding space
st += L' ';
st += arg;
}
return st;
}
template<typename Char>
struct exe_cmd_init : handler_base_ext
{
using value_type = Char;
using string_type = std::basic_string<value_type>;
static const char* c_arg(char) { return "/c";}
static const wchar_t* c_arg(wchar_t) { return L"/c";}
exe_cmd_init(const string_type & exe, bool cmd_only = false)
: exe(exe), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, bool cmd_only = false)
: exe(std::move(exe)), args({}), cmd_only(cmd_only) {};
exe_cmd_init(string_type && exe, std::vector<string_type> && args)
: exe(std::move(exe)), args(build_args(this->exe, std::move(args))), cmd_only(false) {};
template <class Executor>
void on_setup(Executor& exec) const
{
if (cmd_only && args.empty())
exec.cmd_line = exe.c_str();
else
{
exec.exe = exe.c_str();
exec.cmd_line = args.c_str();
}
}
static exe_cmd_init<Char> exe_args(string_type && exe, std::vector<string_type> && args)
{
return exe_cmd_init<Char>(std::move(exe), std::move(args));
}
static exe_cmd_init<Char> cmd(string_type&& cmd)
{
return exe_cmd_init<Char>(std::move(cmd), true);
}
static exe_cmd_init<Char> exe_args_shell(string_type && exe, std::vector<string_type> && args)
{
std::vector<string_type> args_ = {c_arg(Char()), std::move(exe)};
args_.insert(args_.end(), std::make_move_iterator(args.begin()), std::make_move_iterator(args.end()));
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{
std::vector<string_type> args = {c_arg(Char()), std::move(cmd)};
string_type sh = get_shell(Char());
return exe_cmd_init<Char>(
std::move(sh),
std::move(args));
}
private:
string_type exe;
string_type args;
bool cmd_only;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */

View File

@@ -6,14 +6,14 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_PIPE_HPP
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/pipes.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/winapi/get_last_error.hpp>
#include <boost/winapi/access_rights.hpp>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/pipes.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/detail/winapi/get_last_error.hpp>
#include <boost/detail/winapi/access_rights.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/compare_handles.hpp>
#include <system_error>
#include <string>
@@ -24,57 +24,54 @@ namespace boost { namespace process { namespace detail { namespace windows {
template<class CharT, class Traits = std::char_traits<CharT>>
class basic_pipe
{
::boost::winapi::HANDLE_ _source = ::boost::winapi::INVALID_HANDLE_VALUE_;
::boost::winapi::HANDLE_ _sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
::boost::detail::winapi::HANDLE_ _source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
::boost::detail::winapi::HANDLE_ _sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
public:
typedef CharT char_type ;
typedef Traits traits_type;
typedef typename Traits::int_type int_type ;
typedef typename Traits::pos_type pos_type ;
typedef typename Traits::off_type off_type ;
typedef ::boost::winapi::HANDLE_ native_handle_type;
typedef ::boost::detail::winapi::HANDLE_ native_handle_type;
explicit basic_pipe(::boost::winapi::HANDLE_ source, ::boost::winapi::HANDLE_ sink)
explicit basic_pipe(::boost::detail::winapi::HANDLE_ source, ::boost::detail::winapi::HANDLE_ sink)
: _source(source), _sink(sink) {}
inline explicit basic_pipe(const std::string & name);
inline basic_pipe(const basic_pipe& p);
basic_pipe(basic_pipe&& lhs) : _source(lhs._source), _sink(lhs._sink)
{
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
inline basic_pipe& operator=(const basic_pipe& p);
inline basic_pipe& operator=(basic_pipe&& lhs);
~basic_pipe()
{
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink);
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source);
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
}
native_handle_type native_source() const {return _source;}
native_handle_type native_sink () const {return _sink;}
void assign_source(native_handle_type h) { _source = h;}
void assign_sink (native_handle_type h) { _sink = h;}
basic_pipe()
{
if (!::boost::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
if (!::boost::detail::winapi::CreatePipe(&_source, &_sink, nullptr, 0))
throw_last_error("CreatePipe() failed");
}
int_type write(const char_type * data, int_type count)
{
::boost::winapi::DWORD_ write_len;
if (!::boost::winapi::WriteFile(
::boost::detail::winapi::DWORD_ write_len;
if (!::boost::detail::winapi::WriteFile(
_sink, data, count * sizeof(char_type), &write_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "WriteFile failed");
@@ -83,14 +80,14 @@ public:
}
int_type read(char_type * data, int_type count)
{
::boost::winapi::DWORD_ read_len;
if (!::boost::winapi::ReadFile(
::boost::detail::winapi::DWORD_ read_len;
if (!::boost::detail::winapi::ReadFile(
_source, data, count * sizeof(char_type), &read_len, nullptr
))
{
auto ec = ::boost::process::detail::get_last_error();
if ((ec.value() == ::boost::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::winapi::ERROR_NO_DATA_))
if ((ec.value() == ::boost::detail::winapi::ERROR_BROKEN_PIPE_) ||
(ec.value() == ::boost::detail::winapi::ERROR_NO_DATA_))
return 0;
else
throw process_error(ec, "ReadFile failed");
@@ -100,38 +97,38 @@ public:
bool is_open()
{
return (_source != ::boost::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::winapi::INVALID_HANDLE_VALUE_);
return (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_) ||
(_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
void close()
{
::boost::winapi::CloseHandle(_source);
::boost::winapi::CloseHandle(_sink);
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
::boost::detail::winapi::CloseHandle(_source);
::boost::detail::winapi::CloseHandle(_sink);
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
}
};
template<class Char, class Traits>
basic_pipe<Char, Traits>::basic_pipe(const basic_pipe & p)
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
}
@@ -143,23 +140,23 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
static constexpr int FILE_FLAG_OVERLAPPED_ = 0x40000000; //temporary
//static constexpr int FILE_ATTRIBUTE_NORMAL_ = 0x00000080; //temporary
::boost::winapi::HANDLE_ source = ::boost::winapi::create_named_pipe(
::boost::detail::winapi::HANDLE_ source = ::boost::detail::winapi::create_named_pipe(
name.c_str(),
::boost::winapi::PIPE_ACCESS_INBOUND_
::boost::detail::winapi::PIPE_ACCESS_INBOUND_
| FILE_FLAG_OVERLAPPED_, //write flag
0, 1, 8192, 8192, 0, nullptr);
if (source == boost::winapi::INVALID_HANDLE_VALUE_)
if (source == boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_named_pipe() failed");
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
::boost::detail::winapi::HANDLE_ sink = boost::detail::winapi::create_file(
name.c_str(),
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
::boost::detail::winapi::GENERIC_WRITE_, 0, nullptr,
OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read
nullptr);
if (sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
if (sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::process::detail::throw_last_error("create_file() failed");
_source = source;
@@ -169,22 +166,22 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe & p)
{
auto proc = ::boost::winapi::GetCurrentProcess();
auto proc = ::boost::detail::winapi::GetCurrentProcess();
if (p._source == ::boost::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (p._source == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._source, proc, &_source, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
if (p._sink == ::boost::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::winapi::DuplicateHandle(
if (p._sink == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
_sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
else if (!::boost::detail::winapi::DuplicateHandle(
proc, p._sink, proc, &_sink, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
throw_last_error("Duplicate Pipe Failed");
return *this;
@@ -193,16 +190,16 @@ basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(const basic_pipe &
template<class Char, class Traits>
basic_pipe<Char, Traits>& basic_pipe<Char, Traits>::operator=(basic_pipe && lhs)
{
if (_source != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_source);
if (_source != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_source);
if (_sink != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_sink);
if (_sink != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_sink);
_source = lhs._source;
_sink = lhs._sink;
lhs._source = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::winapi::INVALID_HANDLE_VALUE_;
lhs._source = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
lhs._sink = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
return *this;
}

View File

@@ -11,9 +11,9 @@
#define BOOST_PROCESS_WINDOWS_CHILD_HPP
#include <boost/move/move.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/jobs.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/jobs.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -21,18 +21,18 @@ typedef int pid_t;
struct child_handle
{
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
explicit child_handle(const ::boost::winapi::PROCESS_INFORMATION_ &pi) :
explicit child_handle(const ::boost::detail::winapi::PROCESS_INFORMATION_ &pi) :
proc_info(pi)
{}
explicit child_handle(pid_t pid) :
proc_info{nullptr, nullptr, 0,0}
{
auto h = ::boost::winapi::OpenProcess(
::boost::winapi::PROCESS_ALL_ACCESS_,
static_cast<::boost::winapi::BOOL_>(0),
auto h = ::boost::detail::winapi::OpenProcess(
::boost::detail::winapi::PROCESS_ALL_ACCESS_,
static_cast<::boost::detail::winapi::BOOL_>(1),
pid);
if (h == nullptr)
@@ -44,23 +44,23 @@ struct child_handle
child_handle() = default;
~child_handle()
{
::boost::winapi::CloseHandle(proc_info.hProcess);
::boost::winapi::CloseHandle(proc_info.hThread);
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
}
child_handle(const child_handle & c) = delete;
child_handle(child_handle && c) : proc_info(c.proc_info)
{
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
}
child_handle &operator=(const child_handle & c) = delete;
child_handle &operator=(child_handle && c)
{
::boost::winapi::CloseHandle(proc_info.hProcess);
::boost::winapi::CloseHandle(proc_info.hThread);
::boost::detail::winapi::CloseHandle(proc_info.hProcess);
::boost::detail::winapi::CloseHandle(proc_info.hThread);
proc_info = c.proc_info;
c.proc_info.hProcess = ::boost::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::winapi::invalid_handle_value;
c.proc_info.hProcess = ::boost::detail::winapi::invalid_handle_value;
c.proc_info.hThread = ::boost::detail::winapi::invalid_handle_value;
return *this;
}
@@ -69,25 +69,25 @@ struct child_handle
return static_cast<int>(proc_info.dwProcessId);
}
typedef ::boost::winapi::HANDLE_ process_handle_t;
typedef ::boost::detail::winapi::HANDLE_ process_handle_t;
process_handle_t process_handle() const { return proc_info.hProcess; }
bool valid() const
{
return (proc_info.hProcess != nullptr) &&
(proc_info.hProcess != ::boost::winapi::INVALID_HANDLE_VALUE_);
(proc_info.hProcess != ::boost::detail::winapi::INVALID_HANDLE_VALUE_);
}
bool in_group() const
{
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
throw_last_error("IsProcessinJob Failed");
return value!=0;
}
bool in_group(std::error_code &ec) const noexcept
{
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
::boost::detail::winapi::BOOL_ value;
if (!::boost::detail::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
ec = get_last_error();
return value!=0;
}

View File

@@ -10,8 +10,8 @@
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.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 {
@@ -21,8 +21,8 @@ struct close_in : public ::boost::process::detail::handler_base
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdInput = boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdInput = boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
}
};

View File

@@ -10,8 +10,8 @@
#ifndef BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_OUT_HPP
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.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 {
@@ -27,25 +27,25 @@ template<>
template<typename WindowsExecutor>
void close_out<1,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<2,-1>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
template<>
template<typename WindowsExecutor>
void close_out<1,2>::on_setup(WindowsExecutor &e) const
{
e.startup_info.hStdOutput = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.hStdError = ::boost::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.startup_info.hStdOutput = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.hStdError = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
}
}}}}

View File

@@ -1,49 +1,49 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
#include <string>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
template<typename CharType>
struct cmd_setter_ : ::boost::process::detail::handler_base
{
typedef CharType value_type;
typedef std::basic_string<value_type> string_type;
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.cmd_line = _cmd_line.c_str();
}
const string_type & str() const {return _cmd_line;}
private:
string_type _cmd_line;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_CMD_HPP_
#define BOOST_PROCESS_WINDOWS_CMD_HPP_
#include <string>
namespace boost
{
namespace process
{
namespace detail
{
namespace windows
{
template<typename CharType>
struct cmd_setter_ : ::boost::process::detail::handler_base
{
typedef CharType value_type;
typedef std::basic_string<value_type> string_type;
cmd_setter_(string_type && cmd_line) : _cmd_line(std::move(cmd_line)) {}
cmd_setter_(const string_type & cmd_line) : _cmd_line(cmd_line) {}
template <class Executor>
void on_setup(Executor& exec)
{
exec.cmd_line = _cmd_line.c_str();
}
const string_type & str() const {return _cmd_line;}
private:
string_type _cmd_line;
};
}
}
}
}
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */

View File

@@ -6,28 +6,28 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_COMPARE_HANDLES_HPP_
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <boost/process/detail/config.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool compare_handles(boost::winapi::HANDLE_ lhs, boost::winapi::HANDLE_ rhs)
inline bool compare_handles(boost::detail::winapi::HANDLE_ lhs, boost::detail::winapi::HANDLE_ rhs)
{
if ( (lhs == ::boost::winapi::INVALID_HANDLE_VALUE_)
|| (rhs == ::boost::winapi::INVALID_HANDLE_VALUE_))
if ( (lhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
|| (rhs == ::boost::detail::winapi::INVALID_HANDLE_VALUE_))
return false;
if (lhs == rhs)
return true;
::boost::winapi::BY_HANDLE_FILE_INFORMATION_ lhs_info{0,{0,0},{0,0},{0,0},0,0,0,0,0,0};
::boost::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::winapi::GetFileInformationByHandle(lhs, &lhs_info))
if (!::boost::detail::winapi::GetFileInformationByHandle(lhs, &lhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
if (!::boost::winapi::GetFileInformationByHandle(rhs, &rhs_info))
if (!::boost::detail::winapi::GetFileInformationByHandle(rhs, &rhs_info))
::boost::process::detail::throw_last_error("GetFileInformationByHandle");
return (lhs_info.nFileIndexHigh == rhs_info.nFileIndexHigh)

View File

@@ -7,8 +7,7 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_INIT_HPP_
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/error_codes.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::winapi::DWORD_ creation_flag(char) {return 0u;}
constexpr static ::boost::winapi::DWORD_ creation_flag(wchar_t)
{
return ::boost::winapi::CREATE_UNICODE_ENVIRONMENT_;
}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &exec) const
@@ -37,12 +31,11 @@ struct env_init : public ::boost::process::detail::handler_base
auto e = env.native_handle();
if (*e == null_char<char>())
{
exec.set_error(std::error_code(::boost::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
"Empty Environment");
exec.set_error(std::error_code(::boost::detail::winapi::ERROR_BAD_ENVIRONMENT_, std::system_category()),
"Bad Environment");
}
exec.env = e;
exec.creation_flags |= creation_flag(Char());
}
};

View File

@@ -1,354 +1,356 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/winapi/error_codes.hpp>
#include <boost/winapi/environment.hpp>
#include <boost/winapi/get_current_process.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/process/detail/config.hpp>
#include <algorithm>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
class native_environment_impl
{
static void _deleter(Char* p) {boost::winapi::free_environment_strings(p);};
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
static inline std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_buf.get())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
void reload()
{
_buf.reset(boost::winapi::get_environment_strings<Char>());
_env_arr = _load_var(_buf.get());
_env_impl = &*_env_arr.begin();
}
string_type get(const pointer_type id);
void set(const pointer_type id, const pointer_type value);
void reset(const pointer_type id);
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return _buf.get();}
};
template<typename Char>
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
{
Char buf[4096];
auto size = boost::winapi::get_environment_variable(id, buf, sizeof(buf));
if (size == 0) //failed
{
auto err = ::boost::winapi::GetLastError();
if (err == ::boost::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return "";
else
throw process_error(std::error_code(err, std::system_category()),
"GetEnvironmentVariable() failed");
}
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
std::size_t buf_size = sizeof(buf);
while (buf_size <= max_size)
{
std::vector<Char> buf(buf_size);
auto size = boost::winapi::get_environment_variable(id, buf.data(), buf.size());
if (size == buf_size) //buffer to small
buf_size *= 2;
else if (size == 0)
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
{
boost::winapi::set_environment_variable(id, value);
}
template<typename Char>
inline void native_environment_impl<Char>::reset(const pointer_type id)
{
boost::winapi::set_environment_variable(id, nullptr);
}
template<typename Char>
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
struct basic_environment_impl
{
std::vector<Char> _data = {null_char<Char>()};
static std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_data.data())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
std::size_t size() const { return _data.size();}
void reload()
{
_env_arr = _load_var(_data.data());
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
inline basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && rhs)
: _data(std::move(rhs._data)),
_env_arr(std::move(rhs._env_arr)),
_env_impl(_env_arr.data())
{
}
basic_environment_impl &operator=(basic_environment_impl && rhs)
{
_data = std::move(rhs._data);
//reload();
_env_arr = std::move(rhs._env_arr);
_env_impl = _env_arr.data();
return *this;
}
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
reload();
return *this;
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(::boost::process::detail::convert(rhs._data, cv))
{
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return &*_data.begin();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto p = beg;
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++;
p++; //pointing to the second nullchar
p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p);
this->reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end()) //not found
return "";
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
return string_type(&*itr);
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
reset(id);
std::vector<Char> insertion;
insertion.insert(insertion.end(), id.begin(), id.end());
insertion.push_back('=');
insertion.insert(insertion.end(), value.begin(), value.end());
insertion.push_back('\0');
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
//check if it's the first one, spares us the search.
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
{
auto beg = _data.begin();
auto end = beg;
while (*end != '\0')
end++;
end++; //to point behind the last null-char
_data.erase(beg, end); //and remove the thingy
}
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end())
return;//nothing to return if it's empty anyway...
auto end = itr;
while (*++end != '\0');
_data.erase(itr, end);//and remove it
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ';'; }
template<> constexpr wchar_t env_seperator() {return L';'; }
inline int get_id() {return boost::winapi::GetCurrentProcessId();}
inline void* native_handle() {return boost::winapi::GetCurrentProcess(); }
typedef void* native_handle_t;
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_
#include <string>
#include <vector>
#include <unordered_map>
#include <boost/detail/winapi/error_codes.hpp>
#include <boost/detail/winapi/environment.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/detail/winapi/get_current_process.hpp>
#include <boost/detail/winapi/get_current_process_id.hpp>
#include <algorithm>
#include <boost/process/locale.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Char>
class native_environment_impl
{
static void _deleter(Char* p) {boost::detail::winapi::free_environment_strings(p);};
std::unique_ptr<Char[], void(*)(Char*)> _buf{boost::detail::winapi::get_environment_strings<Char>(), &native_environment_impl::_deleter};
static inline std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_buf.get())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
void reload()
{
_buf.reset(boost::detail::winapi::get_environment_strings<Char>());
_env_arr = _load_var(_buf.get());
_env_impl = &*_env_arr.begin();
}
string_type get(const pointer_type id);
void set(const pointer_type id, const pointer_type value);
void reset(const pointer_type id);
string_type get(const string_type & id) {return get(id.c_str());}
void set(const string_type & id, const string_type & value) {set(id.c_str(), value.c_str()); }
void reset(const string_type & id) {reset(id.c_str());}
native_environment_impl() = default;
native_environment_impl(const native_environment_impl& ) = delete;
native_environment_impl(native_environment_impl && ) = default;
native_environment_impl & operator=(const native_environment_impl& ) = delete;
native_environment_impl & operator=(native_environment_impl && ) = default;
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return _buf.get();}
};
template<typename Char>
inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_type
{
Char buf[4096];
auto size = boost::detail::winapi::get_environment_variable(id, buf, sizeof(buf));
if (size == 0) //failed
{
auto err = ::boost::detail::winapi::GetLastError();
if (err == ::boost::detail::winapi::ERROR_ENVVAR_NOT_FOUND_)//well, then we consider that an empty value
return "";
else
throw process_error("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
* but I used 32768 so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
std::size_t buf_size = sizeof(buf);
while (buf_size <= max_size)
{
std::vector<Char> buf(buf_size);
auto size = boost::detail::winapi::get_environment_variable(id, buf.data(), buf.size());
if (size == buf_size) //buffer to small
buf_size *= 2;
else if (size == 0)
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
}
}
return std::basic_string<Char>(buf, buf+size+1);
}
template<typename Char>
inline void native_environment_impl<Char>::set(const pointer_type id, const pointer_type value)
{
boost::detail::winapi::set_environment_variable(id, value);
}
template<typename Char>
inline void native_environment_impl<Char>::reset(const pointer_type id)
{
boost::detail::winapi::set_environment_variable(id, nullptr);
}
template<typename Char>
std::vector<Char*> native_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename Char>
struct basic_environment_impl
{
std::vector<Char> _data = {null_char<Char>()};
static std::vector<Char*> _load_var(Char* p);
std::vector<Char*> _env_arr{_load_var(_data.data())};
public:
using char_type = Char;
using pointer_type = const char_type*;
using string_type = std::basic_string<char_type>;
using native_handle_type = pointer_type;
std::size_t size() const { return _data.size();}
void reload()
{
_env_arr = _load_var(_data.data());
_env_impl = _env_arr.data();
}
string_type get(const pointer_type id) {return get(string_type(id));}
void set(const pointer_type id, const pointer_type value) {set(string_type(id), value);}
void reset(const pointer_type id) {reset(string_type(id));}
string_type get(const string_type & id);
void set(const string_type & id, const string_type & value);
void reset(const string_type & id);
inline basic_environment_impl(const native_environment_impl<Char> & nei);
basic_environment_impl() = default;
basic_environment_impl(const basic_environment_impl& rhs)
: _data(rhs._data)
{
}
basic_environment_impl(basic_environment_impl && rhs)
: _data(std::move(rhs._data)),
_env_arr(std::move(rhs._env_arr)),
_env_impl(_env_arr.data())
{
}
basic_environment_impl &operator=(basic_environment_impl && rhs)
{
_data = std::move(rhs._data);
//reload();
_env_arr = std::move(rhs._env_arr);
_env_impl = _env_arr.data();
return *this;
}
basic_environment_impl & operator=(const basic_environment_impl& rhs)
{
_data = rhs._data;
reload();
return *this;
}
template<typename CharR>
explicit inline basic_environment_impl(
const basic_environment_impl<CharR>& rhs,
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
: _data(::boost::process::detail::convert(rhs._data, cv))
{
}
template<typename CharR>
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
{
_data = ::boost::process::detail::convert(rhs._data);
_env_arr = _load_var(&*_data.begin());
_env_impl = &*_env_arr.begin();
return *this;
}
Char ** _env_impl = &*_env_arr.begin();
native_handle_type native_handle() const {return &*_data.begin();}
};
template<typename Char>
basic_environment_impl<Char>::basic_environment_impl(const native_environment_impl<Char> & nei)
{
auto beg = nei.native_handle();
auto p = beg;
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
p++;
p++; //pointing to the second nullchar
p++; //to get the pointer behing the second nullchar, so it's end.
this->_data.assign(beg, p);
this->reload();
}
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end()) //not found
return "";
itr += seq.size(); //advance to the value behind the '='; the std::string will take care of finding the null-char.
return string_type(&*itr);
}
template<typename Char>
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
{
reset(id);
std::vector<Char> insertion;
insertion.insert(insertion.end(), id.begin(), id.end());
insertion.push_back('=');
insertion.insert(insertion.end(), value.begin(), value.end());
insertion.push_back('\0');
_data.insert(_data.end() -1, insertion.begin(), insertion.end());
reload();
}
template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return;
//check if it's the first one, spares us the search.
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
{
auto beg = _data.begin();
auto end = beg;
while (*end != '\0')
end++;
end++; //to point behind the last null-char
_data.erase(beg, end); //and remove the thingy
}
std::vector<Char> seq = {'\0'}; //using a vector, because strings might cause problems with nullchars
seq.insert(seq.end(), id.begin(), id.end());
seq.push_back('=');
auto itr = std::search(_data.begin(), _data.end(), seq.begin(), seq.end());
if (itr == _data.end())
return;//nothing to return if it's empty anyway...
auto end = itr;
while (*end != '\0')
end++;
end ++; //to point behind the last null-char
_data.erase(itr, end);//and remove it
reload();
}
template<typename Char>
std::vector<Char*> basic_environment_impl<Char>::_load_var(Char* p)
{
std::vector<Char*> ret;
if (*p != null_char<Char>())
{
ret.push_back(p);
while ((*p != null_char<Char>()) || (*(p+1) != null_char<Char>()))
{
if (*p==null_char<Char>())
{
p++;
ret.push_back(p);
}
else
p++;
}
}
p++;
ret.push_back(nullptr);
return ret;
}
template<typename T> constexpr T env_seperator();
template<> constexpr char env_seperator() {return ';'; }
template<> constexpr wchar_t env_seperator() {return L';'; }
inline int get_id() {return boost::detail::winapi::GetCurrentProcessId();}
inline void* native_handle() {return boost::detail::winapi::GetCurrentProcess(); }
typedef void* native_handle_t;
}
}
}
}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_ENV_STORAGE_HPP_ */

View File

@@ -16,14 +16,15 @@
#include <boost/process/detail/traits.hpp>
#include <boost/process/error.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/none.hpp>
#include <system_error>
#include <memory>
#include <atomic>
#include <cstring>
namespace boost { namespace process {
namespace detail { namespace windows {
@@ -33,40 +34,40 @@ template<typename CharType> struct startup_info;
template<> struct startup_info<char>
{
typedef ::boost::winapi::STARTUPINFOA_ type;
typedef ::boost::detail::winapi::STARTUPINFOA_ type;
};
#endif
template<> struct startup_info<wchar_t>
{
typedef ::boost::winapi::STARTUPINFOW_ type;
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;
#if !defined( BOOST_NO_ANSI_APIS )
template<> struct startup_info_ex<char>
{
typedef ::boost::winapi::STARTUPINFOEXA_ type;
typedef ::boost::detail::winapi::STARTUPINFOEXA_ type;
};
#endif
template<> struct startup_info_ex<wchar_t>
{
typedef ::boost::winapi::STARTUPINFOEXW_ type;
typedef ::boost::detail::winapi::STARTUPINFOEXW_ type;
};
#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::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;
@@ -74,18 +75,12 @@ struct startup_info_impl
startup_info_ex_t startup_info_ex
{startup_info_t {sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value},
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value,
::boost::detail::winapi::invalid_handle_value},
nullptr
};
startup_info_t & startup_info = startup_info_ex.StartupInfo;
void set_startup_info_ex()
{
startup_info.cb = sizeof(startup_info_ex_t);
creation_flags = ::boost::winapi::EXTENDED_STARTUPINFO_PRESENT_;
}
startup_info_t & startup_info = startup_info_ex.StartupInfo;
};
@@ -96,26 +91,31 @@ struct startup_info_impl
{
typedef typename startup_info<CharT>::type startup_info_t;
::boost::winapi::DWORD_ creation_flags = 0;
::boost::detail::winapi::DWORD_ creation_flags = 0;
startup_info_t startup_info
{sizeof(startup_info_t), nullptr, nullptr, nullptr,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, nullptr,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value,
::boost::winapi::invalid_handle_value};
::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;
}
@@ -186,7 +186,7 @@ public:
}
//NOTE: The non-cast cmd-line string can only be modified by the wchar_t variant which is currently disabled.
int err_code = ::boost::winapi::create_process(
int err_code = ::boost::detail::winapi::create_process(
exe, // LPCSTR_ lpApplicationName,
const_cast<Char*>(cmd_line), // LPSTR_ lpCommandLine,
proc_attrs, // LPSECURITY_ATTRIBUTES_ lpProcessAttributes,
@@ -232,9 +232,9 @@ public:
const std::error_code& error() const {return _ec;}
::boost::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
::boost::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
::boost::winapi::BOOL_ inherit_handles = false;
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
::boost::detail::winapi::BOOL_ inherit_handles = false;
const Char * work_dir = nullptr;
const Char * cmd_line = nullptr;
const Char * exe = nullptr;
@@ -242,7 +242,7 @@ public:
Sequence & seq;
::boost::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
};

View File

@@ -1,104 +1,104 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
static ::boost::winapi::DWORD_ desired_access(mode_t mode)
{
switch(mode)
{
case read:
return ::boost::winapi::GENERIC_READ_;
case write:
return ::boost::winapi::GENERIC_WRITE_;
case read_write:
return ::boost::winapi::GENERIC_READ_
| ::boost::winapi::GENERIC_WRITE_;
default:
return 0u;
}
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const char* path, mode_t mode = read_write)
: _handle(
::boost::winapi::create_file(
path,
desired_access(mode),
::boost::winapi::FILE_SHARE_READ_ |
::boost::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::winapi::OPEN_ALWAYS_,
::boost::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
::boost::winapi::create_file(
path,
desired_access(mode),
::boost::winapi::FILE_SHARE_READ_ |
::boost::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::winapi::OPEN_ALWAYS_,
::boost::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::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_handle);
}
::boost::winapi::HANDLE_ handle() const { return _handle;}
private:
::boost::winapi::HANDLE_ _handle = ::boost::winapi::INVALID_HANDLE_VALUE_;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_descriptor
{
enum mode_t
{
read = 1,
write = 2,
read_write = 3
};
static ::boost::detail::winapi::DWORD_ desired_access(mode_t mode)
{
switch(mode)
{
case read:
return ::boost::detail::winapi::GENERIC_READ_;
case write:
return ::boost::detail::winapi::GENERIC_WRITE_;
case read_write:
return ::boost::detail::winapi::GENERIC_READ_
| ::boost::detail::winapi::GENERIC_WRITE_;
default:
return 0u;
}
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
file_descriptor(const std::string & path , mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const std::wstring & path, mode_t mode = read_write)
: file_descriptor(path.c_str(), mode) {}
file_descriptor(const char* path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const wchar_t * path, mode_t mode = read_write)
: _handle(
::boost::detail::winapi::create_file(
path,
desired_access(mode),
::boost::detail::winapi::FILE_SHARE_READ_ |
::boost::detail::winapi::FILE_SHARE_WRITE_,
nullptr,
::boost::detail::winapi::OPEN_ALWAYS_,
::boost::detail::winapi::FILE_ATTRIBUTE_NORMAL_,
nullptr
))
{
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
~file_descriptor()
{
if (_handle != ::boost::detail::winapi::INVALID_HANDLE_VALUE_)
::boost::detail::winapi::CloseHandle(_handle);
}
::boost::detail::winapi::HANDLE_ handle() const { return _handle;}
private:
::boost::detail::winapi::HANDLE_ _handle = ::boost::detail::winapi::INVALID_HANDLE_VALUE_;
};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */

View File

@@ -1,44 +1,44 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#include <boost/winapi/process.hpp>
#include <boost/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::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::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_IN_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
#include <io.h>
namespace boost { namespace process { namespace detail { namespace windows {
struct file_in : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_in(T&& t) : file(std::forward<T>(t), file_descriptor::read) {}
file_in(FILE * f) : handle(reinterpret_cast<::boost::detail::winapi::HANDLE_>(_get_osfhandle(_fileno(f)))) {}
template <class WindowsExecutor>
void on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdInput = handle;
e.startup_info.dwFlags |= boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
};
}}}}
#endif

View File

@@ -1,77 +1,77 @@
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/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::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
template <typename WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::winapi::SetHandleInformation(handle,
boost::winapi::HANDLE_FLAG_INHERIT_,
boost::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
#endif
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#define BOOST_PROCESS_DETAIL_WINDOWS_FILE_OUT_HPP
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/detail/winapi/handle_info.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/file_descriptor.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct file_out : public ::boost::process::detail::handler_base
{
file_descriptor file;
::boost::detail::winapi::HANDLE_ handle = file.handle();
template<typename T>
file_out(T&& t) : file(std::forward<T>(t), file_descriptor::write) {}
file_out(FILE * f) : handle(reinterpret_cast<void*>(_get_osfhandle(_fileno(f)))) {}
template <typename WindowsExecutor>
inline void on_setup(WindowsExecutor &e) const;
};
template<>
template<typename WindowsExecutor>
void file_out<1,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<2,-1>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
template<>
template<typename WindowsExecutor>
void file_out<1,2>::on_setup(WindowsExecutor &e) const
{
boost::detail::winapi::SetHandleInformation(handle,
boost::detail::winapi::HANDLE_FLAG_INHERIT_,
boost::detail::winapi::HANDLE_FLAG_INHERIT_);
e.startup_info.hStdOutput = handle;
e.startup_info.hStdError = handle;
e.startup_info.dwFlags |= ::boost::detail::winapi::STARTF_USESTDHANDLES_;
e.inherit_handles = true;
}
}}}}
#endif

View File

@@ -7,14 +7,14 @@
#define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
#include <boost/process/detail/windows/handler.hpp>
#include <boost/winapi/jobs.hpp>
#include <boost/detail/winapi/jobs.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <boost/process/detail/windows/job_workaround.hpp>
#include <system_error>
namespace boost { namespace process { namespace detail { namespace windows {
inline bool break_away_enabled(::boost::winapi::HANDLE_ h)
inline bool break_away_enabled(::boost::detail::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -29,7 +29,7 @@ inline bool break_away_enabled(::boost::winapi::HANDLE_ h)
return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0;
}
inline void enable_break_away(::boost::winapi::HANDLE_ h)
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -54,7 +54,7 @@ inline void enable_break_away(::boost::winapi::HANDLE_ h)
throw_last_error("SetInformationJobObject() failed");
}
inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
inline void enable_break_away(::boost::detail::winapi::HANDLE_ h, std::error_code & ec)
{
workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
@@ -91,9 +91,9 @@ inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
struct group_handle
{
::boost::winapi::HANDLE_ _job_object;
::boost::detail::winapi::HANDLE_ _job_object;
typedef ::boost::winapi::HANDLE_ handle_t;
typedef ::boost::detail::winapi::HANDLE_ handle_t;
handle_t handle() const { return _job_object; }
explicit group_handle(handle_t h) :
@@ -103,52 +103,52 @@ struct group_handle
}
group_handle() : group_handle(::boost::winapi::CreateJobObjectA(nullptr, nullptr))
group_handle() : group_handle(::boost::detail::winapi::CreateJobObjectA(nullptr, nullptr))
{
}
~group_handle()
{
::boost::winapi::CloseHandle(_job_object);
::boost::detail::winapi::CloseHandle(_job_object);
}
group_handle(const group_handle & c) = delete;
group_handle(group_handle && c) : _job_object(c._job_object)
{
c._job_object = ::boost::winapi::invalid_handle_value;
c._job_object = ::boost::detail::winapi::invalid_handle_value;
}
group_handle &operator=(const group_handle & c) = delete;
group_handle &operator=(group_handle && c)
{
::boost::winapi::CloseHandle(_job_object);
::boost::detail::winapi::CloseHandle(_job_object);
_job_object = c._job_object;
c._job_object = ::boost::winapi::invalid_handle_value;
c._job_object = ::boost::detail::winapi::invalid_handle_value;
return *this;
}
void add(handle_t proc)
{
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
throw_last_error();
}
void add(handle_t proc, std::error_code & ec) noexcept
{
if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
ec = get_last_error();
}
bool has(handle_t proc)
{
::boost::winapi::BOOL_ is;
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
throw_last_error();
return is!=0;
}
bool has(handle_t proc, std::error_code & ec) noexcept
{
::boost::winapi::BOOL_ is;
if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
::boost::detail::winapi::BOOL_ is;
if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object, &is))
ec = get_last_error();
return is!=0;
}
@@ -162,13 +162,13 @@ struct group_handle
inline void terminate(const group_handle &p)
{
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
boost::process::detail::throw_last_error("TerminateJobObject() failed");
}
inline void terminate(const group_handle &p, std::error_code &ec) noexcept
{
if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
ec = boost::process::detail::get_last_error();
else
ec.clear();
@@ -176,8 +176,8 @@ inline void terminate(const group_handle &p, std::error_code &ec) noexcept
inline bool in_group()
{
::boost::winapi::BOOL_ res;
if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res))
::boost::detail::winapi::BOOL_ res;
if (!::boost::detail::winapi::IsProcessInJob(boost::detail::winapi::GetCurrentProcess(), nullptr, &res))
throw_last_error("IsProcessInJob failed");
return res!=0;

View File

@@ -8,7 +8,7 @@
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/group_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/process/detail/windows/handler.hpp>
namespace boost { namespace process {
@@ -19,7 +19,7 @@ namespace detail { namespace windows {
struct group_ref : handler_base_ext
{
::boost::winapi::HANDLE_ handle;
::boost::detail::winapi::HANDLE_ handle;
explicit group_ref(group_handle &g) :
handle(g.handle())
@@ -30,14 +30,14 @@ struct group_ref : handler_base_ext
{
//I can only enable this if the current process supports breakaways.
if (in_group() && break_away_enabled(nullptr))
exec.creation_flags |= boost::winapi::CREATE_BREAKAWAY_FROM_JOB_;
exec.creation_flags |= boost::detail::winapi::CREATE_BREAKAWAY_FROM_JOB_;
}
template <class Executor>
void on_success(Executor& exec) const
{
if (!::boost::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
if (!::boost::detail::winapi::AssignProcessToJobObject(handle, exec.proc_info.hProcess))
exec.set_error(::boost::process::detail::get_last_error(),
"AssignProcessToJobObject() failed.");

View File

@@ -1,20 +1,20 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
//does not extend anything.
struct handler_base_ext : handler_base {};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_
#include <boost/process/detail/handler_base.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
//does not extend anything.
struct handler_base_ext : handler_base {};
}}}}
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_HANDLER_HPP_ */

View File

@@ -1,160 +1,160 @@
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <atomic>
#include <vector>
#include <boost/type_index.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
}
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_context_ref : boost::process::detail::handler_base
{
io_context_ref(boost::asio::io_context & ios)
: ios(ios)
{
}
boost::asio::io_context &get() {return ios;};
template <class Executor>
void on_success(Executor& exec) const
{
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
{
return;
}
::boost::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
auto this_proc = ::boost::winapi::GetCurrentProcess();
auto proc_in = proc.hProcess;;
::boost::winapi::HANDLE_ process_handle;
if (!::boost::winapi::DuplicateHandle(
this_proc, proc_in, this_proc, &process_handle, 0,
static_cast<::boost::winapi::BOOL_>(true),
::boost::winapi::DUPLICATE_SAME_ACCESS_))
exec.set_error(::boost::process::detail::get_last_error(),
"Duplicate Pipe Failed");
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
struct wait_handler
{
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::unique_ptr<boost::asio::windows::object_handle> handle;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = delete;
wait_handler(wait_handler && ) = default;
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_context & ios, void * handle,
const std::shared_ptr<std::atomic<int>> &exit_status)
: funcs(std::move(funcs)),
handle(new boost::asio::windows::object_handle(ios, handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
{
std::error_code ec;
if (ec_in)
ec = std::error_code(ec_in.value(), std::system_category());
::boost::winapi::DWORD_ code;
::boost::winapi::GetExitCodeProcess(handle->native_handle(), &code);
exit_status->store(code);
for (auto & func : funcs)
func(code, ec);
}
};
private:
boost::asio::io_context &ios;
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#define BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/detail/winapi/process.hpp>
#include <boost/detail/winapi/handles.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/filter_if.hpp>
#include <boost/fusion/algorithm/transformation/transform.hpp>
#include <boost/fusion/view/transform_view.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <functional>
#include <type_traits>
#include <memory>
#include <atomic>
#include <vector>
#include <boost/type_index.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<typename Executor>
struct on_exit_handler_transformer
{
Executor & exec;
on_exit_handler_transformer(Executor & exec) : exec(exec) {}
template<typename Sig>
struct result;
template<typename T>
struct result<on_exit_handler_transformer<Executor>(T&)>
{
typedef typename T::on_exit_handler_t type;
};
template<typename T>
auto operator()(T& t) const -> typename T::on_exit_handler_t
{
return t.on_exit_handler(exec);
}
};
template<typename Executor>
struct async_handler_collector
{
Executor & exec;
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers;
async_handler_collector(Executor & exec,
std::vector<std::function<void(int, const std::error_code & ec)>> &handlers)
: exec(exec), handlers(handlers) {}
template<typename T>
void operator()(T & t) const
{
handlers.push_back(t.on_exit_handler(exec));
}
};
//Also set's up waiting for the exit, so it can close async stuff.
struct io_service_ref : boost::process::detail::handler_base
{
io_service_ref(boost::asio::io_service & ios)
: ios(ios)
{
}
boost::asio::io_service &get() {return ios;};
template <class Executor>
void on_success(Executor& exec) const
{
auto asyncs = boost::fusion::filter_if<
is_async_handler<
typename std::remove_reference< boost::mpl::_ > ::type
>>(exec.seq);
//ok, check if there are actually any.
if (boost::fusion::empty(asyncs))
{
return;
}
::boost::detail::winapi::PROCESS_INFORMATION_ & proc = exec.proc_info;
auto this_proc = ::boost::detail::winapi::GetCurrentProcess();
auto proc_in = proc.hProcess;;
::boost::detail::winapi::HANDLE_ process_handle;
if (!::boost::detail::winapi::DuplicateHandle(
this_proc, proc_in, this_proc, &process_handle, 0,
static_cast<::boost::detail::winapi::BOOL_>(true),
::boost::detail::winapi::DUPLICATE_SAME_ACCESS_))
exec.set_error(::boost::process::detail::get_last_error(),
"Duplicate Pipe Failed");
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
funcs.reserve(boost::fusion::size(asyncs));
boost::fusion::for_each(asyncs, async_handler_collector<Executor>(exec, funcs));
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
struct wait_handler
{
std::vector<std::function<void(int, const std::error_code & ec)>> funcs;
std::unique_ptr<boost::asio::windows::object_handle> handle;
std::shared_ptr<std::atomic<int>> exit_status;
wait_handler(const wait_handler & ) = delete;
wait_handler(wait_handler && ) = default;
wait_handler(std::vector<std::function<void(int, const std::error_code & ec)>> && funcs,
boost::asio::io_service & ios, void * handle,
const std::shared_ptr<std::atomic<int>> &exit_status)
: funcs(std::move(funcs)),
handle(new boost::asio::windows::object_handle(ios, handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
{
std::error_code ec;
if (ec_in)
ec = std::error_code(ec_in.value(), std::system_category());
::boost::detail::winapi::DWORD_ code;
::boost::detail::winapi::GetExitCodeProcess(handle->native(), &code);
exit_status->store(code);
for (auto & func : funcs)
func(code, ec);
}
};
private:
boost::asio::io_service &ios;
};
}}}}
#endif /* BOOST_PROCESS_WINDOWS_IO_SERVICE_REF_HPP_ */

View File

@@ -9,20 +9,20 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/winapi/process.hpp>
#include <boost/detail/winapi/process.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
constexpr static ::boost::winapi::DWORD_ still_active = 259;
constexpr static ::boost::detail::winapi::DWORD_ still_active = 259;
struct child_handle;
inline bool is_running(const child_handle &p, int & exit_code)
{
::boost::winapi::DWORD_ code;
::boost::detail::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
::boost::process::detail::throw_last_error("GetExitCodeProcess() failed");
if (code == still_active)
@@ -36,9 +36,9 @@ inline bool is_running(const child_handle &p, int & exit_code)
inline bool is_running(const child_handle &p, int & exit_code, std::error_code &ec) noexcept
{
::boost::winapi::DWORD_ code;
::boost::detail::winapi::DWORD_ code;
//single value, not needed in the winapi.
if (!::boost::winapi::GetExitCodeProcess(p.process_handle(), &code))
if (!::boost::detail::winapi::GetExitCodeProcess(p.process_handle(), &code))
ec = ::boost::process::detail::get_last_error();
else
ec.clear();

View File

@@ -6,9 +6,9 @@
#ifndef BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
#define BOOST_PROCESS_DETAIL_WINDOWS_JOB_WORKAROUND_HPP_
#include <boost/winapi/config.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/dll.hpp>
#include <boost/detail/winapi/config.hpp>
#include <boost/detail/winapi/basic_types.hpp>
#include <boost/detail/winapi/dll.hpp>
namespace boost { namespace process { namespace detail { namespace windows { namespace workaround {
@@ -42,35 +42,35 @@ typedef enum _JOBOBJECTINFOCLASS_ {
} JOBOBJECTINFOCLASS_;
typedef struct _JOBOBJECT_BASIC_LIMIT_INFORMATION_ {
::boost::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::winapi::DWORD_ LimitFlags;
::boost::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::winapi::DWORD_ ActiveProcessLimit;
::boost::winapi::ULONG_PTR_ Affinity;
::boost::winapi::DWORD_ PriorityClass;
::boost::winapi::DWORD_ SchedulingClass;
::boost::detail::winapi::LARGE_INTEGER_ PerProcessUserTimeLimit;
::boost::detail::winapi::LARGE_INTEGER_ PerJobUserTimeLimit;
::boost::detail::winapi::DWORD_ LimitFlags;
::boost::detail::winapi::SIZE_T_ MinimumWorkingSetSize;
::boost::detail::winapi::SIZE_T_ MaximumWorkingSetSize;
::boost::detail::winapi::DWORD_ ActiveProcessLimit;
::boost::detail::winapi::ULONG_PTR_ Affinity;
::boost::detail::winapi::DWORD_ PriorityClass;
::boost::detail::winapi::DWORD_ SchedulingClass;
} JOBOBJECT_BASIC_LIMIT_INFORMATION_;
typedef struct _IO_COUNTERS_ {
::boost::winapi::ULONGLONG_ ReadOperationCount;
::boost::winapi::ULONGLONG_ WriteOperationCount;
::boost::winapi::ULONGLONG_ OtherOperationCount;
::boost::winapi::ULONGLONG_ ReadTransferCount;
::boost::winapi::ULONGLONG_ WriteTransferCount;
::boost::winapi::ULONGLONG_ OtherTransferCount;
::boost::detail::winapi::ULONGLONG_ ReadOperationCount;
::boost::detail::winapi::ULONGLONG_ WriteOperationCount;
::boost::detail::winapi::ULONGLONG_ OtherOperationCount;
::boost::detail::winapi::ULONGLONG_ ReadTransferCount;
::boost::detail::winapi::ULONGLONG_ WriteTransferCount;
::boost::detail::winapi::ULONGLONG_ OtherTransferCount;
} IO_COUNTERS_;
typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
JOBOBJECT_BASIC_LIMIT_INFORMATION_ BasicLimitInformation;
IO_COUNTERS_ IoInfo;
::boost::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::winapi::SIZE_T_ JobMemoryLimit;
::boost::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::winapi::SIZE_T_ PeakJobMemoryUsed;
::boost::detail::winapi::SIZE_T_ ProcessMemoryLimit;
::boost::detail::winapi::SIZE_T_ JobMemoryLimit;
::boost::detail::winapi::SIZE_T_ PeakProcessMemoryUsed;
::boost::detail::winapi::SIZE_T_ PeakJobMemoryUsed;
} JOBOBJECT_EXTENDED_LIMIT_INFORMATION_;
@@ -82,23 +82,23 @@ typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ {
_Out_opt_ LPDWORD lpReturnLength
);
*/
typedef ::boost::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
::boost::winapi::HANDLE_,
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *query_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::winapi::DWORD_,
::boost::winapi::DWORD_ *);
::boost::detail::winapi::DWORD_,
::boost::detail::winapi::DWORD_ *);
inline ::boost::winapi::BOOL_ WINAPI query_information_job_object(
::boost::winapi::HANDLE_ hJob,
inline ::boost::detail::winapi::BOOL_ WINAPI query_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength,
::boost::winapi::DWORD_ *lpReturnLength)
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength,
::boost::detail::winapi::DWORD_ *lpReturnLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::winapi::get_proc_address(h, "QueryInformationJobObject"));
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static query_information_job_object_p f = reinterpret_cast<query_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "QueryInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength, lpReturnLength);
}
@@ -110,27 +110,27 @@ inline ::boost::winapi::BOOL_ WINAPI query_information_job_object(
_In_ DWORD cbJobObjectInfoLength
);*/
typedef ::boost::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
::boost::winapi::HANDLE_,
typedef ::boost::detail::winapi::BOOL_ ( WINAPI *set_information_job_object_p)(
::boost::detail::winapi::HANDLE_,
JOBOBJECTINFOCLASS_,
void *,
::boost::winapi::DWORD_);
::boost::detail::winapi::DWORD_);
}
inline ::boost::winapi::BOOL_ WINAPI set_information_job_object(
::boost::winapi::HANDLE_ hJob,
inline ::boost::detail::winapi::BOOL_ WINAPI set_information_job_object(
::boost::detail::winapi::HANDLE_ hJob,
JOBOBJECTINFOCLASS_ JobObjectInfoClass,
void * lpJobObjectInfo,
::boost::winapi::DWORD_ cbJobObjectInfoLength)
::boost::detail::winapi::DWORD_ cbJobObjectInfoLength)
{
static ::boost::winapi::HMODULE_ h = ::boost::winapi::get_module_handle("Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::winapi::get_proc_address(h, "SetInformationJobObject"));
static ::boost::detail::winapi::HMODULE_ h = ::boost::detail::winapi::get_module_handle("Kernel32.dll");
static set_information_job_object_p f = reinterpret_cast<set_information_job_object_p>(::boost::detail::winapi::get_proc_address(h, "SetInformationJobObject"));
return (*f)(hJob, JobObjectInfoClass, lpJobObjectInfo, cbJobObjectInfoLength);
}
constexpr static ::boost::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
constexpr static ::boost::detail::winapi::DWORD_ JOB_OBJECT_LIMIT_BREAKAWAY_OK_ = 0x00000800;
}}}}}

Some files were not shown because too many files have changed in this diff Show More