mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
1 Commits
boost-1.88
...
variant
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85345157d3 |
@@ -1,75 +0,0 @@
|
||||
version: 2
|
||||
|
||||
jobs:
|
||||
build:
|
||||
environment:
|
||||
- BOOST_LIBRARY=process
|
||||
- CXX_STANDARD=gnu++11
|
||||
docker:
|
||||
- image: gcc:7
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Setting up Environment
|
||||
command: |
|
||||
echo 'export BOOST="$HOME/boost-local"' >> $BASH_ENV
|
||||
if [ $CIRCLE_BRANCH = "master" ]; then
|
||||
echo 'export BOOST_BRANCH="master"' >> $BASH_ENV;
|
||||
else
|
||||
echo 'export BOOST_BRANCH="develop"' >> $BASH_ENV;
|
||||
fi
|
||||
echo 'export BOOST_REMOVE="$BOOST/libs/$BOOST_LIBRARY"' >> $BASH_ENV
|
||||
HOME_SED_=$(echo $HOME | sed -e 's/\//\\\//g')
|
||||
echo 'export HOME_SED=$HOME_SED_' >> $BASH_ENV
|
||||
- run:
|
||||
name: install pre dependencies
|
||||
command: |
|
||||
apt-get update -yqq
|
||||
apt-get install git curl valgrind -y
|
||||
- run:
|
||||
name: Initializing git repo for boost
|
||||
command: |
|
||||
git init $BOOST
|
||||
cd $BOOST
|
||||
echo Testing $BRANCH_TO_TEST
|
||||
git remote add --no-tags -t $BOOST_BRANCH origin https://github.com/boostorg/boost.git
|
||||
git fetch --depth=1
|
||||
git checkout $BOOST_BRANCH
|
||||
git submodule update --init --merge
|
||||
git remote set-branches --add origin $BOOST_BRANCH
|
||||
git pull --recurse-submodules
|
||||
git submodule update --init
|
||||
git checkout $BOOST_BRANCH
|
||||
git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
git reset --hard; git clean -fxd
|
||||
git status
|
||||
rm -rf $BOOST_REMOVE
|
||||
mv $HOME/project $BOOST_REMOVE
|
||||
- run:
|
||||
name: Bootstrapping boost-build
|
||||
command: |
|
||||
cd $BOOST
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- run:
|
||||
name: Building examples
|
||||
command: |
|
||||
cd $BOOST_REMOVE/example
|
||||
../../../b2 -j2 address-model=64 architecture=x86 toolset=gcc cxxflags="-std=gnu++14" -sBOOST_BUILD_PATH=. | tee example.log || FAILED=1
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" example.log
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --name "Circle CI Gcc Build" --input example.log
|
||||
exit $FAILED
|
||||
- run:
|
||||
name: Running Unit tests
|
||||
command: |
|
||||
cd $BOOST_REMOVE/test
|
||||
../../../b2 -j2 with-valgrind address-model=64 architecture=x86 testing.launcher=valgrind valgrind=on toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee test.log || FAILED=1
|
||||
../../../b2 -j2 without-valgrind address-model=64 architecture=x86 toolset=gcc cxxflags="--coverage -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. | tee no-valgrind.log || FAILED=1
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" test.log
|
||||
sed -i -e "s/^..\/..\/..\/boost\/process\//\/root\/project\/include\/boost\/process\//gm" no-valgrind.log
|
||||
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input test.log
|
||||
python <(curl -s https://report.ci/annotate.py) --tool gcc --input no-valgrind.log
|
||||
bash <(curl -s https://codecov.io/bash) -x gcov > /dev/null || true
|
||||
echo "BUILD_RESULT: $FAILED"
|
||||
exit $FAILED
|
||||
38
.drone.star
38
.drone.star
@@ -1,38 +0,0 @@
|
||||
# Use, modification, and distribution are
|
||||
# subject to the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE.txt)
|
||||
#
|
||||
# Copyright Rene Rivera 2020.
|
||||
|
||||
# For Drone CI we use the Starlark scripting language to reduce duplication.
|
||||
# As the yaml syntax for Drone CI is rather limited.
|
||||
#
|
||||
#
|
||||
globalenv={'B2_CI_VERSION': '1', 'B2_VARIANT': 'release'}
|
||||
linuxglobalimage="cppalliance/droneubuntu1804:1"
|
||||
windowsglobalimage="cppalliance/dronevs2019"
|
||||
|
||||
def main(ctx):
|
||||
return [
|
||||
#freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
|
||||
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
|
||||
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
|
||||
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
|
||||
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
|
||||
#linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
|
||||
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb",
|
||||
image="cppalliance/droneubuntu2004:1", buildtype="boost", buildscript="drone", environment={"GCOV": "gcov-10", "LCOV_VERSION": "1.15", "VARIANT": "process_coverage", "TOOLSET": "gcc", "COMPILER": "g++-10", "CXXSTD": "11", "DRONE_BEFORE_INSTALL" : "process_coverage", "CODECOV_TOKEN": {"from_secret": "codecov_token"}}, globalenv=globalenv, privileged=True),
|
||||
# A set of jobs based on the earlier .travis.yml configuration:
|
||||
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
|
||||
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
|
||||
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
|
||||
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
|
||||
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
|
||||
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
|
||||
linux_cxx("coverity", "g++", packages="", buildtype="coverity", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'Coverity Scan', 'B2_TOOLSET': 'clang', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
|
||||
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.1", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
|
||||
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.3", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
|
||||
]
|
||||
|
||||
# from https://github.com/boostorg/boost-ci
|
||||
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")
|
||||
@@ -1,34 +0,0 @@
|
||||
@ECHO ON
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
if "%DRONE_JOB_BUILDTYPE%" == "boost" (
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
|
||||
cp -prf boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
REM source ci/travis/install.sh
|
||||
REM The contents of install.sh below:
|
||||
|
||||
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
|
||||
SET BOOST_CI_TARGET_BRANCH=%DRONE_COMMIT_BRANCH%
|
||||
SET BOOST_CI_SRC_FOLDER=%cd%
|
||||
|
||||
call ci\common_install.bat
|
||||
|
||||
echo '==================================> COMPILE'
|
||||
|
||||
REM set B2_TARGETS=libs/!SELF!/test libs/!SELF!/example
|
||||
set B2_TARGETS=libs/!SELF!/test
|
||||
|
||||
cd !BOOST_ROOT!
|
||||
call bootstrap.bat
|
||||
b2 headers
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
|
||||
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
|
||||
|
||||
REM not used
|
||||
|
||||
)
|
||||
199
.drone/drone.sh
199
.drone/drone.sh
@@ -1,199 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2020 Rene Rivera, Sam Darwin
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set -xe
|
||||
|
||||
export TRAVIS_BUILD_DIR=$(pwd)
|
||||
export DRONE_BUILD_DIR=$(pwd)
|
||||
export TRAVIS_BRANCH=$DRONE_BRANCH
|
||||
export TRAVIS_EVENT_TYPE=$DRONE_BUILD_EVENT
|
||||
export VCS_COMMIT_ID=$DRONE_COMMIT
|
||||
export GIT_COMMIT=$DRONE_COMMIT
|
||||
export REPO_NAME=$DRONE_REPO
|
||||
export USER=$(whoami)
|
||||
export CC=${CC:-gcc}
|
||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
||||
|
||||
common_install () {
|
||||
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
|
||||
cp -prf boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
unset -f cd
|
||||
fi
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
export BOOST_CI_TARGET_BRANCH="$TRAVIS_BRANCH"
|
||||
export BOOST_CI_SRC_FOLDER=$(pwd)
|
||||
|
||||
. ./ci/common_install.sh
|
||||
}
|
||||
|
||||
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
$BOOST_ROOT/libs/$SELF/ci/travis/build.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "docs" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
|
||||
pwd
|
||||
cd ..
|
||||
mkdir -p $HOME/cache && cd $HOME/cache
|
||||
if [ ! -d doxygen ]; then git clone -b 'Release_1_8_15' --depth 1 https://github.com/doxygen/doxygen.git && echo "not-cached" ; else echo "cached" ; fi
|
||||
cd doxygen
|
||||
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
|
||||
cd build
|
||||
sudo make install
|
||||
cd ../..
|
||||
if [ ! -f saxonhe.zip ]; then wget -O saxonhe.zip https://sourceforge.net/projects/saxon/files/Saxon-HE/9.9/SaxonHE9-9-1-4J.zip/download && echo "not-cached" ; else echo "cached" ; fi
|
||||
unzip -o saxonhe.zip
|
||||
sudo rm /usr/share/java/Saxon-HE.jar
|
||||
sudo cp saxon9he.jar /usr/share/java/Saxon-HE.jar
|
||||
cd ..
|
||||
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root --depth 1
|
||||
cd boost-root
|
||||
export BOOST_ROOT=$(pwd)
|
||||
git submodule update --init libs/context
|
||||
git submodule update --init tools/boostbook
|
||||
git submodule update --init tools/boostdep
|
||||
git submodule update --init tools/docca
|
||||
git submodule update --init tools/quickbook
|
||||
rsync -av $TRAVIS_BUILD_DIR/ libs/$SELF
|
||||
python tools/boostdep/depinst/depinst.py ../tools/quickbook
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
echo "using doxygen ; using boostbook ; using saxonhe ;" > tools/build/src/user-config.jam
|
||||
./b2 -j3 libs/$SELF/doc//boostrelease
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "codecov" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/codecov.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "valgrind" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/valgrind.sh
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "standalone" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
# Installing cmake with apt-get, so not required here:
|
||||
# pip install --user cmake
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
export CXXFLAGS="-Wall -Wextra -Werror -std=c++17"
|
||||
mkdir __build_17
|
||||
cd __build_17
|
||||
cmake -DBOOST_JSON_STANDALONE=1 ..
|
||||
cmake --build .
|
||||
ctest -V .
|
||||
export CXXFLAGS="-Wall -Wextra -Werror -std=c++2a"
|
||||
mkdir ../__build_2a
|
||||
cd ../__build_2a
|
||||
cmake -DBOOST_JSON_STANDALONE=1 ..
|
||||
cmake --build .
|
||||
ctest -V .
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "coverity" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
if [ $VARIANT = "process_valgrind" ];
|
||||
then export USE_VALGRIND="testing.launcher=valgrind valgrind=on";
|
||||
fi ;
|
||||
|
||||
if [ -n "${COVERITY_SCAN_NOTIFICATION_EMAIL}" -a \( "$TRAVIS_BRANCH" = "develop" -o "$TRAVIS_BRANCH" = "master" \) -a \( "$DRONE_BUILD_EVENT" = "push" -o "$DRONE_BUILD_EVENT" = "cron" \) ] ; then
|
||||
cd $BOOST_ROOT/libs/$SELF
|
||||
ci/travis/coverity.sh
|
||||
fi
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake-superproject" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
common_install
|
||||
|
||||
echo '==================================> COMPILE'
|
||||
|
||||
export CXXFLAGS="-Wall -Wextra -Werror"
|
||||
|
||||
mkdir __build_static
|
||||
cd __build_static
|
||||
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
|
||||
-DBOOST_INCLUDE_LIBRARIES=$SELF ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure -R boost_$SELF
|
||||
|
||||
cd ..
|
||||
|
||||
mkdir __build_shared
|
||||
cd __build_shared
|
||||
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
|
||||
-DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=ON ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure -R boost_$SELF
|
||||
|
||||
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake1" ]; then
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
pip install --user cmake
|
||||
|
||||
echo '==================================> SCRIPT'
|
||||
|
||||
export SELF=`basename $REPO_NAME`
|
||||
BOOST_BRANCH=develop && [ "$DRONE_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
mkdir -p libs/$SELF
|
||||
cp -r $DRONE_BUILD_DIR/* libs/$SELF
|
||||
# git submodule update --init tools/boostdep
|
||||
git submodule update --init --recursive
|
||||
|
||||
cd libs/$SELF
|
||||
|
||||
../../../b2 -sBOOST_BUILD_PATH=.
|
||||
../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
|
||||
|
||||
|
||||
fi
|
||||
96
.gitattributes
vendored
96
.gitattributes
vendored
@@ -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
|
||||
193
.github/workflows/ci.yml
vendored
193
.github/workflows/ci.yml
vendored
@@ -1,193 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { toolset: gcc-5, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-5 }
|
||||
- { toolset: gcc-6, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: g++-6 }
|
||||
- { toolset: gcc-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: g++-7 }
|
||||
- { toolset: gcc-10, cxxstd: "11,14,17,2a", os: ubuntu-22.04, install: g++-10 }
|
||||
- { toolset: gcc-12, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: g++-12 }
|
||||
- { toolset: clang, compiler: clang++-3.9, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-3.9 }
|
||||
- { toolset: clang, compiler: clang++-4.0, cxxstd: "11,14", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-4.0 }
|
||||
- { toolset: clang, compiler: clang++-5.0, cxxstd: "11,14,1z", os: ubuntu-latest, container: 'ubuntu:18.04', install: clang-5.0 }
|
||||
- { toolset: clang, compiler: clang++-6.0, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-6.0 }
|
||||
- { toolset: clang, compiler: clang++-7, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-7 }
|
||||
- { toolset: clang, compiler: clang++-8, cxxstd: "11,14,17", os: ubuntu-20.04, install: clang-8 }
|
||||
- { toolset: clang, compiler: clang++-9, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-9 }
|
||||
- { toolset: clang, compiler: clang++-10, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-10 }
|
||||
- { toolset: clang, compiler: clang++-11, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-11 }
|
||||
- { toolset: clang, compiler: clang++-12, cxxstd: "11,14,17,2a", os: ubuntu-20.04, install: clang-12 }
|
||||
- { toolset: clang, compiler: clang++-13, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-13 }
|
||||
- { toolset: clang, compiler: clang++-14, cxxstd: "11,14,17,20,2b", os: ubuntu-22.04, install: clang-14 }
|
||||
- { toolset: clang, cxxstd: "11,14,17,2a", os: macos-13 }
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
container:
|
||||
image: ${{matrix.container}}
|
||||
volumes:
|
||||
- /node20217:/node20217:rw,rshared
|
||||
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
|
||||
|
||||
steps:
|
||||
- name: Setup container environment
|
||||
if: matrix.container
|
||||
run: |
|
||||
apt-get update
|
||||
apt-get -y install sudo python3 git g++ curl
|
||||
if [[ "${{matrix.container}}" == "ubuntu:1"* ]]; then
|
||||
# Node 20 doesn't work with Ubuntu 16/18 glibc: https://github.com/actions/checkout/issues/1590
|
||||
curl -sL https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz | tar -xJ --strip-components 1 -C /node20217
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt-get -y install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Create user-config.jam
|
||||
if: matrix.compiler
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
|
||||
|
||||
alpine-linux:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:3.20.1
|
||||
steps:
|
||||
- name: Install packages
|
||||
run: apk add g++ git python3 linux-headers
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=gcc cxxstd=23 variant=debug,release
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: "14,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.2
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: gcc
|
||||
cxxstd: "11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
|
||||
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
|
||||
echo LIBRARY: %LIBRARY%
|
||||
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
|
||||
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
|
||||
echo GITHUB_REF: %GITHUB_REF%
|
||||
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,5 +31,4 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
|
||||
184
.travis.yml
184
.travis.yml
@@ -10,6 +10,28 @@
|
||||
#
|
||||
# File revision #6
|
||||
|
||||
env:
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# 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
|
||||
|
||||
matrix:
|
||||
- CXX_STANDARD=c++11 TOOLSET=gcc-5
|
||||
- CXX_STANDARD=c++1y TOOLSET=gcc-5
|
||||
|
||||
|
||||
###############################################################################################################
|
||||
# From this point and below code is same for all the Boost libs
|
||||
@@ -17,120 +39,80 @@
|
||||
sudo: false
|
||||
language: cpp
|
||||
compiler:
|
||||
- gcc
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BADGE=linux
|
||||
- BADGE=osx
|
||||
global:
|
||||
# Autodetect Boost branch by using the following code: - BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
# or just directly specify it
|
||||
- BRANCH_TO_TEST=$TRAVIS_BRANCH
|
||||
|
||||
# Files, which coverage results must be ignored (files from other projects).
|
||||
# Example: - IGNORE_COVERAGE='*/boost/progress.hpp */filesystem/src/*'
|
||||
- IGNORE_COVERAGE=''
|
||||
|
||||
# Explicitly remove the following library from Boost. This may be usefull, if you're for example running Travis
|
||||
# from `Boost.DLL` repo, while Boost already has `dll`.
|
||||
#
|
||||
# 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
|
||||
- CXX_STANDARD=gnu++11
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: linux
|
||||
env: BADGE=osx
|
||||
- os: osx
|
||||
env: BADGE=linux
|
||||
|
||||
|
||||
- linux
|
||||
|
||||
# Installing additional tools
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
- valgrind
|
||||
- python-yaml
|
||||
- gcc-5
|
||||
- g++-5
|
||||
# - lcov
|
||||
- clang
|
||||
|
||||
before_install:
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
- if [ $TRAVIS_OS_NAME = "osx" ]; then brew install gcc5; brew install valgrind; brew install llvm; TOOLSET=clang; BOOST_TEST_CATCH_SYSTEM_ERRORS=no; MULTITHREAD=-j8; else TOOLSET=gcc-5; REPORT_CI=--boost-process-report-ci USE_VALGRIND="testing.launcher=valgrind valgrind=on"; fi
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- echo Branch to test $BRANCH_TO_TEST
|
||||
- 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
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules || true
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- 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
|
||||
- mv $TRAVIS_BUILD_DIR/../$PROJECT_TO_TEST/ $BOOST/libs/$PROJECT_TO_TEST
|
||||
- TRAVIS_BUILD_DIR=$BOOST/libs/$PROJECT_TO_TEST
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- echo BOOST_TEST_CATCH_SYSTEM_ERRORS $BOOST_TEST_CATCH_SYSTEM_ERRORS
|
||||
# Set this to the name of the library
|
||||
- PROJECT_TO_TEST=`basename $TRAVIS_BUILD_DIR`
|
||||
- echo "Testing $PROJECT_TO_TEST"
|
||||
# Cloning Boost libraries (fast nondeep cloning)
|
||||
- BOOST=$HOME/boost-local
|
||||
- git init $BOOST
|
||||
- cd $BOOST
|
||||
- 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
|
||||
- git fetch --depth=1
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
- git reset --hard; git clean -fxd
|
||||
- git status
|
||||
# - 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
|
||||
- ./b2 headers
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
|
||||
script:
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
- ../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- ../../../b2 testing.launcher=valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=.
|
||||
|
||||
after_success:
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
# Copying Coveralls data to a separate folder
|
||||
- mkdir -p $TRAVIS_BUILD_DIR/coverals
|
||||
- find ../../../bin.v2/ -name "*.gcda" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
- find ../../../bin.v2/ -name "*.gcno" -exec cp "{}" $TRAVIS_BUILD_DIR/coverals/ \;
|
||||
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
|
||||
- GCOV_VERSION=""
|
||||
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
|
||||
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
# Preparing Coveralls data by changind data format to a readable one
|
||||
- git clone https://github.com/linux-test-project/lcov.git lcov_dir
|
||||
- GCOV_VERSION=""
|
||||
- if [[ "$TOOLSET" == *"-"* ]]; then GCOV_VERSION="--gcov-tool gcov-${TOOLSET#*-}"; fi
|
||||
- LCOV="$BOOST/libs/$PROJECT_TO_TEST/test/lcov_dir/bin/lcov $GCOV_VERSION"
|
||||
- $LCOV --directory $TRAVIS_BUILD_DIR/coverals --base-directory ./ --capture --output-file $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "*.cpp" "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
# ... erasing /test/ /example/ folder data
|
||||
- cd $BOOST
|
||||
- $LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info "/usr*" "*/$PROJECT_TO_TEST/test/*" $IGNORE_COVERAGE "*/$PROJECT_TO_TEST/tests/*" "*/$PROJECT_TO_TEST/examples/*" "*/$PROJECT_TO_TEST/example/*" -o $TRAVIS_BUILD_DIR/coverals/coverage.info
|
||||
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/process\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info" > /dev/null
|
||||
# ... erasing data that is not related to this project directly
|
||||
- OTHER_LIBS=`grep "submodule .*" .gitmodules | sed 's/\[submodule\ "\(.*\)"\]/"\*\/boost\/\1\.hpp" "\*\/boost\/\1\/\*"/g'| sed "/\"\*\/boost\/$PROJECT_TO_TEST\/\*\"/d" | sed ':a;N;$!ba;s/\n/ /g'`
|
||||
- echo $OTHER_LIBS
|
||||
- eval "$LCOV --remove $TRAVIS_BUILD_DIR/coverals/coverage.info $OTHER_LIBS -o $TRAVIS_BUILD_DIR/coverals/coverage.info"
|
||||
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
- cd $BOOST/libs/$PROJECT_TO_TEST/test
|
||||
- curl -s https://report.ci/report.py | python - --name="$BADGE test run"
|
||||
# Sending data to Coveralls
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- gem install coveralls-lcov
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
# Generated by `boostdep --cmake process`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_process
|
||||
src/detail/environment_posix.cpp
|
||||
src/detail/environment_win.cpp
|
||||
src/detail/last_error.cpp
|
||||
src/detail/process_handle_windows.cpp
|
||||
src/detail/throw_error.cpp
|
||||
src/detail/utf8.cpp
|
||||
src/ext/cmd.cpp
|
||||
src/ext/cwd.cpp
|
||||
src/ext/env.cpp
|
||||
src/ext/exe.cpp
|
||||
src/ext/proc_info.cpp
|
||||
src/posix/close_handles.cpp
|
||||
src/windows/default_launcher.cpp
|
||||
src/environment.cpp
|
||||
src/error.cpp
|
||||
src/pid.cpp
|
||||
src/shell.cpp)
|
||||
|
||||
add_library(Boost::process ALIAS boost_process)
|
||||
|
||||
target_include_directories(boost_process PUBLIC include)
|
||||
target_link_libraries(boost_process
|
||||
PUBLIC
|
||||
Boost::algorithm
|
||||
Boost::asio
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::fusion
|
||||
Boost::iterator
|
||||
Boost::move
|
||||
Boost::optional
|
||||
Boost::system
|
||||
Boost::tokenizer
|
||||
Boost::type_index
|
||||
Boost::winapi
|
||||
)
|
||||
|
||||
target_compile_definitions(boost_process
|
||||
PRIVATE BOOST_PROCESS_SOURCE=1
|
||||
)
|
||||
|
||||
if (BOOST_PROCESS_USE_STD_FS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
|
||||
else()
|
||||
target_link_libraries(boost_process PUBLIC Boost::filesystem)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32 ws2_32)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_DYN_LINK)
|
||||
else()
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_STATIC_LINK)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
22
README.md
22
README.md
@@ -1,21 +1,17 @@
|
||||
# [Boost Process (Boost.Process)](https://github.com/boostorg/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 | Linux / Windows | Code coverage | Matrix |
|
||||
|----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Develop: | [](https://drone.cpp.al/boostorg/process) | [](https://codecov.io/gh/boostorg/process) | [](http://www.boost.org/development/tests/develop/developer/process.html) |
|
||||
| Master: | [](https://drone.cpp.al/boostorg/process) | [](https://codecov.io/gh/boostorg/process) | [](http://www.boost.org/development/tests/master/developer/process.html) |
|
||||
Branches | Build | Tests coverage |
|
||||
----------------|-------------- | -------------- |
|
||||
Develop: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) |
|
||||
Master: | [] (https://travis-ci.org/klemens-morgenstern/boost-process) [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) |
|
||||
|
||||
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
|
||||
|
||||
|
||||
|
||||
|
||||
[Open Issues](https://github.com/boostorg/process/issues)
|
||||
|
||||
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
|
||||
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
|
||||
|
||||
### About
|
||||
This C++11 library is the current result of a long attempt to get a boost.process library, which is going on since 2006.
|
||||
@@ -25,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.
|
||||
|
||||
47
build.jam
47
build.jam
@@ -1,47 +0,0 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2024
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
import feature : feature ;
|
||||
|
||||
feature boost.process.fs : boost std : optional propagated ;
|
||||
feature boost.process.disable-close-range : on off : optional ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/algorithm//boost_algorithm
|
||||
/boost/asio//boost_asio
|
||||
/boost/assert//boost_assert
|
||||
/boost/config//boost_config
|
||||
/boost/core//boost_core
|
||||
/boost/fusion//boost_fusion
|
||||
/boost/io//boost_io
|
||||
/boost/iterator//boost_iterator
|
||||
/boost/move//boost_move
|
||||
/boost/optional//boost_optional
|
||||
/boost/system//boost_system
|
||||
/boost/throw_exception//boost_throw_exception
|
||||
/boost/tokenizer//boost_tokenizer
|
||||
/boost/type_index//boost_type_index
|
||||
/boost/type_traits//boost_type_traits
|
||||
/boost/utility//boost_utility
|
||||
/boost/winapi//boost_winapi ;
|
||||
|
||||
project /boost/process
|
||||
: common-requirements
|
||||
<include>include
|
||||
: default-build
|
||||
<boost.process.fs>boost
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_process : build//boost_process ]
|
||||
[ alias all : boost_process example example/v2 test ]
|
||||
;
|
||||
|
||||
call-if : boost-library process
|
||||
: install boost_process
|
||||
;
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
# Copyright (c) 2024 Klemens D. Morgenstern
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os ;
|
||||
import feature ;
|
||||
import-search /boost/config/checks ;
|
||||
import config : requires ;
|
||||
|
||||
project : requirements
|
||||
<define>BOOST_ASIO_NO_DEPRECATED
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
: source-location ../src
|
||||
: common-requirements
|
||||
<library>$(boost_dependencies)
|
||||
<boost.process.fs>std:<define>BOOST_PROCESS_USE_STD_FS=1
|
||||
;
|
||||
|
||||
alias process_sources
|
||||
: detail/environment_posix.cpp
|
||||
detail/environment_win.cpp
|
||||
detail/last_error.cpp
|
||||
detail/process_handle_windows.cpp
|
||||
detail/throw_error.cpp
|
||||
detail/utf8.cpp
|
||||
ext/cmd.cpp
|
||||
ext/cwd.cpp
|
||||
ext/env.cpp
|
||||
ext/exe.cpp
|
||||
ext/proc_info.cpp
|
||||
posix/close_handles.cpp
|
||||
windows/default_launcher.cpp
|
||||
environment.cpp
|
||||
error.cpp
|
||||
pid.cpp
|
||||
shell.cpp
|
||||
;
|
||||
|
||||
lib shell32 ;
|
||||
lib advapi32 ;
|
||||
lib ntdll ;
|
||||
lib user32 ;
|
||||
lib ws2_32 ;
|
||||
|
||||
lib kvm ;
|
||||
lib procstat ;
|
||||
|
||||
lib boost_process
|
||||
: process_sources
|
||||
: requirements <define>BOOST_PROCESS_SOURCE=1
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
<boost.process.disable-close-range>on:<define>BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE=1
|
||||
<target-os>windows:<library>shell32
|
||||
<target-os>windows:<library>user32
|
||||
<target-os>windows:<library>ntdll
|
||||
<target-os>windows:<library>advapi32
|
||||
<target-os>windows:<library>ws2_32
|
||||
<target-os>bsd:<library>kvm
|
||||
<target-os>freebsd:<library>kvm
|
||||
<target-os>freebsd:<library>procstat
|
||||
<target-os>netbsd:<library>kvm
|
||||
<target-os>openbsd:<library>kvm
|
||||
<target-os>solaris:<library>kvm
|
||||
: usage-requirements
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
;
|
||||
@@ -1,31 +1,31 @@
|
||||
# Copyright 2022 Klemens D. Morgenstern
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
# 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)
|
||||
|
||||
import asciidoctor ;
|
||||
using boostbook ;
|
||||
using quickbook ;
|
||||
using doxygen ;
|
||||
|
||||
html index.html : index.adoc ;
|
||||
|
||||
install html_ : index.html : <location>html ;
|
||||
|
||||
pdf process.pdf : index.adoc ;
|
||||
explicit process.pdf ;
|
||||
|
||||
install pdf_ : process.pdf : <location>pdf ;
|
||||
explicit pdf_ ;
|
||||
|
||||
install images
|
||||
:
|
||||
images/posix_exec_err.svg
|
||||
images/posix_fork_err.svg
|
||||
images/posix_success.svg
|
||||
images/windows_exec.svg
|
||||
:
|
||||
<location>html/images
|
||||
;
|
||||
|
||||
alias boostdoc ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease : html_ ;
|
||||
explicit boostrelease ;
|
||||
doxygen autodoc
|
||||
:
|
||||
../../../boost/process.hpp
|
||||
[ glob ../../../boost/process/*.hpp ]
|
||||
:
|
||||
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=YES
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
;
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
process.qbk
|
||||
:
|
||||
<dependency>autodoc
|
||||
<xsl:param>boost.root=../../../..
|
||||
<xsl:param>html.stylesheet=../../../../doc/src/boostbook.css
|
||||
;
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
= Acknowledgements
|
||||
[section Acknowledgements]
|
||||
|
||||
The first Boost.Process draft was created in 2006. A lof of people have worked on various drafts since then. Especially Merino Vidal, Ilya Sokolov and Felipe Tanus spent a lot of time working on early drafts. They influenced Boost.Process over the years and wrote code which, to various extents, is still around in the library today.
|
||||
|
||||
The design of earlier versions of Boost.Process was not always satisfying. In 2011 Jeff Flinn proposed the executor and initializer concepts Boost.Process is based on today. Without Jeff's idea the overall design of Boost.Process would not look like it does today.
|
||||
|
||||
A special thank you goes to [http://www.intra2net.com/(Intra2net AG) (especially Thomas Jarosch) who sponsored a project to support the development of Boost.Process. It was this sponsorship which made it possible to create a new Boost.Process version in 2012.
|
||||
A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especially Thomas Jarosch) who sponsored a project to support the development of Boost.Process. It was this sponsorship which made it possible to create a new Boost.Process version in 2012.
|
||||
|
||||
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
|
||||
|
||||
Many Thanks, to [https://github.com/time-killer-games](Samuel Venable) for contributing the <<v2::ext>> functionality and all the research that went into it.
|
||||
|
||||
|
||||
[endsect]
|
||||
@@ -1,11 +0,0 @@
|
||||
= Configuration
|
||||
|
||||
Boost process v2 can be configured in the following ways:
|
||||
|
||||
[cols="1,1"]
|
||||
|===
|
||||
| Macro | Description
|
||||
|
||||
| `BOOST_PROCESS_V2_STANDALONE` | Build boost.process for standalone asio
|
||||
| `BOOST_PROCESS_USE_STD_FS` | Use std::filesystem instead of boost::filesystem
|
||||
| `BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE` | Disable usage of `close_range`.
|
||||
93
doc/design.qbk
Normal file
93
doc/design.qbk
Normal file
@@ -0,0 +1,93 @@
|
||||
[section:design Design Rationale]
|
||||
[section Scope]
|
||||
This library is meant to give an wrapper around the different OS-specific methods
|
||||
to launch processes. Its aim is to provide all functionality that is available on
|
||||
those systems and allow the user to do all related things, which require using the OS APIs.
|
||||
|
||||
[*This library does not try to provide a full library for everything process related]
|
||||
In many discussions the proposal was made to build boost.process into a DSEL [footnote Domain Specific Embedded Language] of some sort.
|
||||
This is not the goal, it rather provides the facilities to build such a DSEL-Library on top of it.
|
||||
Therefore the library also does [*not] force any particular use (such as only asynchronous communication) on its user.
|
||||
It rather could be integrated with such a library.
|
||||
|
||||
[endsect]
|
||||
[section Interface Style]
|
||||
|
||||
Boost.Process does use a very particular style when constructing a process.
|
||||
This is because a process holds many properties, which are not members of the actual child class.
|
||||
Those properties are in many cases not accessible by the father process, for example when using environments.
|
||||
Here the child process can modify its own environment, but there is no way for the father process to know.
|
||||
That means, that a child process has properties that cannot be accessed in C++.
|
||||
|
||||
This now leads to the two styles supported and mixed by this library. Overloading and properties.
|
||||
Consider that you may want to launch a process passing a number of arguments. This is supported in both styles, and would look like this:
|
||||
|
||||
```
|
||||
system("gcc", "--version"); //overloading
|
||||
system("gcc", args={"--version"}); //property style.
|
||||
```
|
||||
|
||||
Both styles can also be mixed in some cases.
|
||||
|
||||
```
|
||||
system("gcc", "-c", args+={"main.cpp"});
|
||||
```
|
||||
|
||||
In the following section the avaible styles will be described. Note that the
|
||||
overload style is implemented via type traits, so the types will be listed.
|
||||
|
||||
[caution There is no guarantee in which order the arguments will be applied!
|
||||
There is however a guarantee for arguments belonging together, i.e. the string
|
||||
argument and the args property will be evaluated in the order given.]
|
||||
|
||||
[endsect]
|
||||
[section:arg_cmd_style Arguments/Command Style]
|
||||
|
||||
When passing arguments to the process, two styles are provided, the cmd-style and the exe-/args-style.
|
||||
|
||||
The cmd style will interpret the string as a sequence of the exe and arguments and parse them as such, while the exe-/args-style will
|
||||
interpret each string as an argument.
|
||||
|
||||
[table:id Cmd vs Exe/Args
|
||||
[[String] [Cmd] [Exe/Args]]
|
||||
[["gcc --version"] [{"gcc", "--version"}] [{"\\"gcc --version\\""}]]
|
||||
]
|
||||
|
||||
When using the overloading variant, a single string will result in a cmd interpretation,
|
||||
several strings will yield a exe-args interpretation. Both version can be set explicitly:
|
||||
|
||||
```
|
||||
system("grep -c false /etc/passwd"); //cmd style
|
||||
system("grep", "-c", "false", "/etc/passwd"); //exe-/args-
|
||||
|
||||
system(cmd="grep -c false /etc/passwd"); //cmd style
|
||||
system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
|
||||
```
|
||||
|
||||
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
|
||||
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note On windows the path will only be searched for the executable in the command style.]
|
||||
[endsect]
|
||||
|
||||
[section:plat_ext Extensions]
|
||||
|
||||
The simplest form to extend functionality is to provide another handler, which
|
||||
will be called on the respective events on process launching. The names are:
|
||||
|
||||
*`boost::process::on_setup`
|
||||
*`boost::process::on_error`
|
||||
*`boost::process::on_success`
|
||||
|
||||
|
||||
As an example:
|
||||
|
||||
```
|
||||
child c("ls", on_setup([](){cout << "On Setup" << endl;});
|
||||
```
|
||||
|
||||
|
||||
[note On posix all those callbacks will be handled by this process, not the created one.
|
||||
This is different for the posix extensions, which can be executed on the forked process.]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
31
doc/env.adoc
31
doc/env.adoc
@@ -1,31 +0,0 @@
|
||||
== Environment
|
||||
|
||||
The `environment` namespace provides all sorts of facilities to query and manipulate the environment of the current process.
|
||||
|
||||
The api should be straight forward, but one oddity that needs to be pointed out is, that environment names
|
||||
are not case sensitive on windows. The key_traits class implements the proper traits depending on the current system.
|
||||
|
||||
Additionally, environment can be lists separated by `:` or `;`; `environment::value` and
|
||||
`environment::value_view` can be used to iterate those.
|
||||
|
||||
Beyond that, the requirements on an environment are a low as possible;
|
||||
an environment is either a list of strings or a list of string-pairs. It is however recommended to use the environment types,
|
||||
as to have the right value comparisons.
|
||||
|
||||
To note is the `find_executable` functions, which searches in an environment for an executable.
|
||||
|
||||
.example/env.cpp:19-28
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/env.cpp[tag=current_env]
|
||||
----
|
||||
|
||||
== Subprocess environment
|
||||
|
||||
The subprocess environment assignment follows the same constraints:
|
||||
|
||||
.example/env.cpp:34-42
|
||||
[source,cpp,ident=0]
|
||||
----
|
||||
include::../example/env.cpp[tag=subprocess_env]
|
||||
----
|
||||
87
doc/faq.qbk
Normal file
87
doc/faq.qbk
Normal file
@@ -0,0 +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 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]
|
||||
@@ -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 |
@@ -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 |
@@ -1,51 +0,0 @@
|
||||
= boost.process
|
||||
Klemens Morgenstern <klemens.morgenstern@gmx.net>
|
||||
Version 2.0, 19.11.2024
|
||||
:source-highlighter: rouge
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:icons: font
|
||||
:idprefix:
|
||||
:docinfo: private-footer
|
||||
:source-highlighter: rouge
|
||||
:source-language: c++
|
||||
:example-caption: Example
|
||||
|
||||
:imagesdir: ./images
|
||||
|
||||
:leveloffset: +1
|
||||
|
||||
include::quickstart.adoc[]
|
||||
include::launcher.adoc[]
|
||||
|
||||
= Initializers
|
||||
|
||||
include::start_dir.adoc[]
|
||||
include::stdio.adoc[]
|
||||
include::env.adoc[]
|
||||
|
||||
= Reference
|
||||
|
||||
|
||||
include::reference/bind_launcher.adoc[]
|
||||
include::reference/cstring_ref.adoc[]
|
||||
include::reference/default_launcher.adoc[]
|
||||
include::reference/environment.adoc[]
|
||||
include::reference/error.adoc[]
|
||||
include::reference/execute.adoc[]
|
||||
include::reference/exit_code.adoc[]
|
||||
include::reference/ext.adoc[]
|
||||
include::reference/pid.adoc[]
|
||||
include::reference/popen.adoc[]
|
||||
include::reference/process.adoc[]
|
||||
include::reference/process_handle.adoc[]
|
||||
include::reference/shell.adoc[]
|
||||
include::reference/start_dir.adoc[]
|
||||
include::reference/stdio.adoc[]
|
||||
include::reference/ext.adoc[]
|
||||
include::reference/posix/bind_fd.adoc[]
|
||||
include::reference/windows/creation_flags.adoc[]
|
||||
include::reference/windows/show_window.adoc[]
|
||||
|
||||
include::version2.adoc[]
|
||||
include::acknowledgements.adoc[]
|
||||
24
doc/introduction.qbk
Normal file
24
doc/introduction.qbk
Normal file
@@ -0,0 +1,24 @@
|
||||
[section:introduction Introduction]
|
||||
|
||||
Boost.Process is a library to manage system processes. It can be used to:
|
||||
|
||||
* create child processes
|
||||
* setup streams for child processes
|
||||
* communicate with child processes through streams (synchronously or asynchronously)
|
||||
* wait for processes to exit (synchronously or asynchronously)
|
||||
* terminate processes
|
||||
|
||||
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 boost/process.hpp [headerref boost/process.hpp boost/process.hpp]]
|
||||
|
||||
|
||||
[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]
|
||||
@@ -1,126 +0,0 @@
|
||||
= Launcher
|
||||
|
||||
The process creation is done by a process_launcher.
|
||||
The constructor of `process` will use the default_launcher, which varies by system.
|
||||
There are additional launcher available on most systems.
|
||||
|
||||
[cols="1,1,1,1"]
|
||||
|===
|
||||
|Name | Summary | Default on | Available on
|
||||
|
||||
|
||||
|
||||
|
||||
|`windows::default_launcher` | `CreateProcessW` | windows |windows
|
||||
|`windows::as_user_launcher` | `CreateProcessAsUserW` | |windows
|
||||
|`windows::with_logon_launcher` | `CreateProcessWithLogonW` | |windows
|
||||
|`windows::with_token_launcher` | `CreateProcessWithTokenW` | |windows
|
||||
|`posix::default_launcher` | fork & an error pipe | most of posix |posix
|
||||
|`posix::fork_and_forget` | fork without error pipe | |posix
|
||||
|`posix::vfork_launcher` | vfork | |posix
|
||||
|===
|
||||
|
||||
A launcher is invoked through the call operator.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
|
||||
asio::io_context ctx;
|
||||
boost::system::error_code ec;
|
||||
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
|
||||
----
|
||||
|
||||
The launcher will call certain functions on the initializer if they're present, as documented below.
|
||||
The initializer are used to modify the process behaviour.
|
||||
|
||||
|
||||
== Linux Launchers
|
||||
|
||||
The default launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
|
||||
|
||||
NOTE: A pipe can be used if one end is open on the parent, the other on the child.
|
||||
This allows the parents to select on his pipe-end to know if the child exited.
|
||||
|
||||
This can be prevented by using the `fork_and_forget_launcher`.
|
||||
Alternatively, the `vfork_launcher` can report errors directly back to the parent process.
|
||||
|
||||
Thus some calls to the initializers occur after forking from the child process.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
struct custom_initializer
|
||||
{
|
||||
// called before a call to fork. A returned error will cancel the launch.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred when forking, in addition to on_error.
|
||||
template<typename Launcher>
|
||||
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
|
||||
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
|
||||
template<typename Launcher>
|
||||
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
|
||||
// called after a failed call to execve from the child process.
|
||||
template<typename Launcher>
|
||||
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
};
|
||||
----
|
||||
|
||||
The call sequence on success:
|
||||
|
||||
image::posix_success.svg[]
|
||||
|
||||
The call sequence when fork fails:
|
||||
|
||||
image::posix_fork_err.svg[]
|
||||
|
||||
The call sequence when exec fails:
|
||||
|
||||
image::posix_exec_err.svg[]
|
||||
|
||||
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
|
||||
|
||||
== Windows Launchers
|
||||
|
||||
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
struct custom_initializer
|
||||
{
|
||||
// called before a call to CreateProcess. A returned error will cancel the launch.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
// called for every initializer if an error occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
};
|
||||
----
|
||||
|
||||
NTOE: All the additional launchers for windows inherit `default_launcher`.
|
||||
|
||||
The call sequence is as follows:
|
||||
|
||||
image::windows_exec.svg
|
||||
'''
|
||||
19
doc/process.qbk
Normal file
19
doc/process.qbk
Normal file
@@ -0,0 +1,19 @@
|
||||
[library Boost.Process
|
||||
[quickbook 1.5]
|
||||
[authors [Morgenstern, Klemens David]]
|
||||
[copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 Julio M. Merino Vidal, Ilya Sokolov, Felipe Tanus, Jeff Flinn, Boris Schaeling, 2016 Klemens D. Morgenstern]
|
||||
[id process]
|
||||
[dirname process]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include tutorial.qbk]
|
||||
[include design.qbk]
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[include acknowledgements.qbk]
|
||||
@@ -1,104 +0,0 @@
|
||||
= Quickstart
|
||||
|
||||
A process needs four things to be launched:
|
||||
|
||||
* an asio execution_context / executor
|
||||
* a path to an executable
|
||||
* a list of arguments
|
||||
* a variadic set of initializers
|
||||
|
||||
.example/quickstart.cpp:13-17
|
||||
[source,cpp,indent=0]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=cp]
|
||||
----
|
||||
<1> The executor for the process handle
|
||||
<2> The Path to the executable
|
||||
<3> The argument list in the form of an `std::initializer_list`.
|
||||
<4> Not additional initializers
|
||||
|
||||
The started process can then be awaited or terminated.
|
||||
|
||||
== Lifetime
|
||||
|
||||
If the process handle goes out of scope, it will terminate the subprocess.
|
||||
You can prevent this, by calling `proc.detach()`; do however note that this
|
||||
can lead to zombie processes.
|
||||
|
||||
A process that completed will deliver an exit-code,
|
||||
which can be obtained by calling `.exit_code` on the exited process and which is
|
||||
also returned from `.wait()`.
|
||||
|
||||
.example/quickstart.cpp:22-23
|
||||
[source,cpp, indent=0]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=ls]
|
||||
----
|
||||
|
||||
The normal exit-code is what the subprocess returned from `main`;
|
||||
posix will however add additional information about the process.
|
||||
This is called the `native_exit_code`.
|
||||
|
||||
|
||||
The `.running()` function can be used to detect if the process is still active.
|
||||
|
||||
|
||||
== Signalling the subprocess
|
||||
|
||||
The parent process can signal the subprocess demanding certain actions.
|
||||
|
||||
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||||
This is the only reliable & portable way to end a subprocess.
|
||||
|
||||
.example/quickstart.cpp:28-29
|
||||
[source,cpp,indent=0]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=terminate]
|
||||
----
|
||||
|
||||
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
|
||||
which the subprocess might ignore.
|
||||
|
||||
.example/quickstart.cpp:34-36
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=request_exit]
|
||||
----
|
||||
|
||||
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
|
||||
interpret as a signal for shutdown.
|
||||
|
||||
WARNING: interrupt requires the initializer `windows::create_new_process_group` to be set on windows
|
||||
|
||||
.example/quickstart.cpp:41-43
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=interrupt]
|
||||
----
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:execute Execute functions]
|
||||
|
||||
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
|
||||
|
||||
.example/quickstart.cpp:48
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=execute]
|
||||
----
|
||||
|
||||
The async version supports cancellation and will forward cancellation types as follows:
|
||||
|
||||
- `asio::cancellation_type::total` -> interrupt
|
||||
- `asio::cancellation_type::partial` -> request_exit
|
||||
- `asio::cancellation_type::terminal` -> terminate
|
||||
|
||||
.example/quickstart.cpp:53-56
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/quickstart.cpp[tag=async_execute]
|
||||
----
|
||||
<1> After 10 seconds send a request_exit.
|
||||
<2> After 20 seconds terminate
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
== `bind_launcher.hpp`
|
||||
|
||||
The `bind_launcher` utlitities allow on the fly construction of a launcher with bound initializers.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// Creates a new launcher with the bound initializer.
|
||||
template<typename Launcher, typename ... Init>
|
||||
auto bind_launcher(Launcher && launcher, Init && ... init);
|
||||
|
||||
// Calls bind_launcher with the default_launcher as the first parameter.
|
||||
// The new launcher with bound parameters
|
||||
template<typename ... Init>
|
||||
auto bind_default_launcher(Init && ... init);
|
||||
----
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
== `cstring_ref.hpp`
|
||||
|
||||
The `cstring_ref` is a string-view like type that holds a null-terminated string.
|
||||
@@ -1,22 +0,0 @@
|
||||
== `default_launcher.hpp`
|
||||
[#default_launcher]
|
||||
|
||||
The `default_launcher` is the standard way of creating a process.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
asio::io_context ctx;
|
||||
process proc(ctx.get_executor(), "test", {});
|
||||
// equivalent to
|
||||
process prod = default_launcher()(ctx.get_executor(), "test", {});
|
||||
----
|
||||
|
||||
It has four overloads:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
(ExecutionContext &, filesystem::path, Args && args, Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
|
||||
(Executor &, filesystem::path, Args && args, Inits && ... inits) -> basic_process<Executor>;
|
||||
(ExecutionContext &, error_code&, filesystem::path, Args && args, Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>;`
|
||||
(Executor &, error_code&, filesystem::path, Args && args, Inits && ... inits) -> basic_process<Executor>
|
||||
----
|
||||
@@ -1,735 +0,0 @@
|
||||
== `environment.hpp`
|
||||
[#environment]
|
||||
|
||||
=== `environment`
|
||||
|
||||
The `environment` header provides facilities to maniuplate the current environment and set it for new processes.
|
||||
|
||||
|
||||
An environment is a a `range` of `T` fulfilling these requirements:
|
||||
|
||||
For `T value`
|
||||
* - std::get<0>(value) must return a type comparable to `key_view`.
|
||||
* - std::get<1>(value) must return a type convertible to `value_view`.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
// Namespace for information and functions regarding the calling process.
|
||||
namespace environment
|
||||
{
|
||||
|
||||
// A char traits type that reflects the OS rules for string representing environment keys.
|
||||
/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
|
||||
*
|
||||
* Windows treats keys as case-insensitive yet perserving. The char traits are made to reflect
|
||||
* that behaviour.
|
||||
*/
|
||||
template<typename Char>
|
||||
using key_char_traits = implementation_defined ;
|
||||
|
||||
// A char traits type that reflects the OS rules for string representing environment values.
|
||||
/* Can be an alias of std::char_traits. May only be defined for `char` and `wchar_t`.
|
||||
*/
|
||||
template<typename Char>
|
||||
using value_char_traits = implementation_defined ;
|
||||
|
||||
// The character type used by the environment. Either `char` or `wchar_t`.
|
||||
using char_type = implementation_defined ;
|
||||
|
||||
// The equal character in an environment string used to separate key and value.
|
||||
constexpr char_type equality_sign = implementation_defined;
|
||||
|
||||
// The delimiter in environemtn lists. Commonly used by the `PATH` variable.
|
||||
constexpr char_type delimiter = implementation_defined;
|
||||
|
||||
// The native handle of an environment. Note that this can be an owning pointer and is generally not thread safe.
|
||||
using native_handle = implementation_defined;
|
||||
|
||||
|
||||
// A forward iterator over string_view used by a value or value_view to iterator through environments that are lists.
|
||||
struct value_iterator;
|
||||
|
||||
// A view type for a key of an environment
|
||||
struct key_view
|
||||
{
|
||||
using value_type = char_type;
|
||||
using traits_type = key_char_traits<char_type>;
|
||||
using string_view_type = basic_string_view<char_type, traits_type>;
|
||||
using string_type = std::basic_string<char_type, key_char_traits<char_type>>;
|
||||
|
||||
key_view() noexcept = default;
|
||||
key_view( const key_view& p ) = default;
|
||||
key_view( key_view&& p ) noexcept = default;
|
||||
template<typename Source>
|
||||
key_view( const Source& source );
|
||||
key_view( const char_type * p);
|
||||
key_view( char_type * p);
|
||||
|
||||
~key_view() = default;
|
||||
|
||||
key_view& operator=( const key_view& p ) = default;
|
||||
key_view& operator=( key_view&& p ) noexcept = default;
|
||||
key_view& operator=( string_view_type source );
|
||||
|
||||
void swap( key_view& other ) noexcept;
|
||||
|
||||
string_view_type native() const noexcept;
|
||||
|
||||
operator string_view_type() const;
|
||||
|
||||
int compare( const key_view& p ) const noexcept;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>,
|
||||
class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc()) const;
|
||||
|
||||
std::string string() const;
|
||||
std::wstring wstring() const;
|
||||
|
||||
string_type native_string() const;
|
||||
|
||||
friend bool operator==(key_view l, key_view r);
|
||||
friend bool operator!=(key_view l, key_view r);
|
||||
friend bool operator<=(key_view l, key_view r);
|
||||
friend bool operator>=(key_view l, key_view r);
|
||||
friend bool operator< (key_view l, key_view r);
|
||||
friend bool operator> (key_view l, key_view r);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const key_view& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, key_view& p );
|
||||
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
// A view for a value in an environment
|
||||
struct value_view
|
||||
{
|
||||
using value_type = char_type;
|
||||
using string_view_type = basic_cstring_ref<char_type, value_char_traits<char_type>>;
|
||||
using string_type = std::basic_string<char_type, value_char_traits<char_type>>;
|
||||
using traits_type = value_char_traits<char_type>;
|
||||
|
||||
value_view() noexcept = default;
|
||||
value_view( const value_view& p ) = default;
|
||||
value_view( value_view&& p ) noexcept = default;
|
||||
template<typename Source>
|
||||
value_view( const Source& source );
|
||||
value_view( const char_type * p);
|
||||
value_view( char_type * p);
|
||||
|
||||
~value_view() = default;
|
||||
|
||||
value_view& operator=( const value_view& p ) = default;
|
||||
value_view& operator=( value_view&& p ) noexcept = default;
|
||||
value_view& operator=( string_view_type source );
|
||||
|
||||
void swap( value_view& other ) noexcept;
|
||||
|
||||
string_view_type native() const noexcept ;
|
||||
|
||||
operator string_view_type() const;
|
||||
operator typename string_view_type::string_view_type() const;
|
||||
|
||||
int compare( const value_view& p ) const noexcept;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>,
|
||||
class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc() ) const;
|
||||
std::string string() const;
|
||||
std::wstring wstring() const;
|
||||
|
||||
string_type native_string() const;
|
||||
bool empty() const;
|
||||
|
||||
friend bool operator==(value_view l, value_view r);
|
||||
friend bool operator!=(value_view l, value_view r);
|
||||
friend bool operator<=(value_view l, value_view r);
|
||||
friend bool operator>=(value_view l, value_view r);
|
||||
friend bool operator< (value_view l, value_view r);
|
||||
friend bool operator> (value_view l, value_view r);
|
||||
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const value_view& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, value_view& p );
|
||||
value_iterator begin() const;
|
||||
value_iterator end() const;
|
||||
|
||||
const char_type * c_str();
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
// A view for a key value pair in an environment
|
||||
struct key_value_pair_view
|
||||
{
|
||||
using value_type = char_type;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using string_view_type = basic_cstring_ref<char_type>;
|
||||
using traits_type = std::char_traits<char_type>;
|
||||
|
||||
key_value_pair_view() noexcept = default;
|
||||
key_value_pair_view( const key_value_pair_view& p ) = default;
|
||||
key_value_pair_view( key_value_pair_view&& p ) noexcept = default;
|
||||
template<typename Source,
|
||||
typename = typename std::enable_if<is_constructible<string_view_type, Source>::value>::type>
|
||||
key_value_pair_view( const Source& source );
|
||||
|
||||
key_value_pair_view( const char_type * p);
|
||||
key_value_pair_view( char_type * p);
|
||||
|
||||
|
||||
~key_value_pair_view() = default;
|
||||
|
||||
key_value_pair_view& operator=( const key_value_pair_view& p ) = default;
|
||||
key_value_pair_view& operator=( key_value_pair_view&& p ) noexcept = default;
|
||||
|
||||
void swap( key_value_pair_view& other ) noexcept;
|
||||
|
||||
string_view_type native() const noexcept;
|
||||
|
||||
operator string_view_type() const;
|
||||
operator typename string_view_type::string_view_type() const;
|
||||
|
||||
int compare( key_value_pair_view p ) const noexcept;
|
||||
int compare( const string_type& str ) const;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>, class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc()) const;
|
||||
std::string string() const;
|
||||
std::wstring wstring() const;
|
||||
|
||||
string_type native_string() const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
key_view key() const;
|
||||
value_view value() const;
|
||||
|
||||
friend bool operator==(key_value_pair_view l, key_value_pair_view r);
|
||||
friend bool operator!=(key_value_pair_view l, key_value_pair_view r);
|
||||
friend bool operator<=(key_value_pair_view l, key_value_pair_view r);
|
||||
friend bool operator>=(key_value_pair_view l, key_value_pair_view r);
|
||||
friend bool operator< (key_value_pair_view l, key_value_pair_view r);
|
||||
friend bool operator> (key_value_pair_view l, key_value_pair_view r);
|
||||
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const key_value_pair_view& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, key_value_pair_view& p );
|
||||
|
||||
template<std::size_t Idx>
|
||||
inline auto get() const -> typename conditional<Idx == 0u, key_view,
|
||||
value_view>::type;
|
||||
const value_type * c_str() const noexcept;
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
|
||||
};
|
||||
|
||||
// Allow tuple-likg getters & structured bindings.
|
||||
template<> key_view key_value_pair_view::get<0u>() const;
|
||||
template<> value_view key_value_pair_view::get<1u>() const;
|
||||
|
||||
// A class representing a key within an environment.
|
||||
struct key
|
||||
{
|
||||
using value_type = char_type;
|
||||
using traits_type = key_char_traits<char_type>;
|
||||
using string_type = std::basic_string<char_type, traits_type>;
|
||||
using string_view_type = basic_string_view<char_type, traits_type>;
|
||||
|
||||
key();
|
||||
key( const key& p ) = default;
|
||||
key( key&& p ) noexcept = default;
|
||||
key( const string_type& source );
|
||||
key( string_type&& source );
|
||||
key( const value_type * raw );
|
||||
key( value_type * raw );
|
||||
|
||||
explicit key(key_view kv);
|
||||
|
||||
|
||||
template< class Source >
|
||||
key( const Source& source);
|
||||
|
||||
key(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type * raw);
|
||||
|
||||
template< class InputIt >
|
||||
key( InputIt first, InputIt last);
|
||||
|
||||
~key() = default;
|
||||
|
||||
key& operator=( const key& p ) = default;
|
||||
key& operator=( key&& p );
|
||||
key& operator=( string_type&& source );
|
||||
|
||||
template< class Source >
|
||||
key& operator=( const Source& source );
|
||||
|
||||
key& assign( string_type&& source );
|
||||
|
||||
template< class Source >
|
||||
key& assign( const Source& source );
|
||||
template< class InputIt >
|
||||
key& assign( InputIt first, InputIt last );
|
||||
|
||||
void clear();
|
||||
|
||||
void swap( key& other ) noexcept;
|
||||
|
||||
const value_type* c_str() const noexcept;
|
||||
const string_type& native() const noexcept;
|
||||
string_view_type native_view() const noexcept;
|
||||
|
||||
operator string_type() const;
|
||||
operator string_view_type() const;
|
||||
|
||||
int compare( const key& p ) const noexcept;
|
||||
int compare( const string_type& str ) const;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>,
|
||||
class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc()) const;
|
||||
|
||||
|
||||
std::string string() const;
|
||||
std::wstring wstring() const;
|
||||
|
||||
const string_type & native_string() const;
|
||||
bool empty() const;
|
||||
|
||||
friend bool operator==(const key & l, const key & r);
|
||||
friend bool operator!=(const key & l, const key & r);
|
||||
friend bool operator<=(const key & l, const key & r);
|
||||
friend bool operator>=(const key & l, const key & r);
|
||||
friend bool operator< (const key & l, const key & r);
|
||||
friend bool operator> (const key & l, const key & r);
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const key& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, key& p );
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
bool operator==(const value_view &, const value_view);
|
||||
bool operator!=(const value_view &, const value_view);
|
||||
bool operator<=(const value_view &, const value_view);
|
||||
bool operator< (const value_view &, const value_view);
|
||||
bool operator> (const value_view &, const value_view);
|
||||
bool operator>=(const value_view &, const value_view);
|
||||
|
||||
|
||||
struct value
|
||||
{
|
||||
using value_type = char_type;
|
||||
using traits_type = value_char_traits<char_type>;
|
||||
using string_type = std::basic_string<char_type, traits_type>;
|
||||
using string_view_type = basic_cstring_ref<char_type, traits_type>;
|
||||
|
||||
value();
|
||||
value( const value& p ) = default;
|
||||
|
||||
value( const string_type& source );
|
||||
value( string_type&& source );
|
||||
value( const value_type * raw );
|
||||
value( value_type * raw );
|
||||
|
||||
explicit value(value_view kv);
|
||||
|
||||
template< class Source >
|
||||
value( const Source& source );
|
||||
value(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type * raw);
|
||||
|
||||
template< class InputIt >
|
||||
value( InputIt first, InputIt last);
|
||||
|
||||
~value() = default;
|
||||
|
||||
value& operator=( const value& p ) = default;
|
||||
value& operator=( value&& p );
|
||||
value& operator=( string_type&& source );
|
||||
template< class Source >
|
||||
value& operator=( const Source& source );
|
||||
|
||||
value& assign( string_type&& source );
|
||||
template< class Source >
|
||||
value& assign( const Source& source );
|
||||
|
||||
template< class InputIt >
|
||||
value& assign( InputIt first, InputIt last );
|
||||
|
||||
void push_back(const value & sv);
|
||||
void clear() {value_.clear();}
|
||||
|
||||
void swap( value& other ) noexcept;
|
||||
|
||||
const value_type* c_str() const noexcept;
|
||||
const string_type& native() const noexcept;
|
||||
string_view_type native_view() const noexcept;
|
||||
|
||||
operator string_type() const;
|
||||
operator string_view_type() const;
|
||||
operator typename string_view_type::string_view_type() const;
|
||||
|
||||
int compare( const value& p ) const noexcept;
|
||||
int compare( const string_type& str ) const;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>,
|
||||
class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc()) const;
|
||||
|
||||
std::string string() const;
|
||||
std::wstring wstring() const;
|
||||
|
||||
|
||||
const string_type & native_string() const;
|
||||
|
||||
bool empty() const;
|
||||
|
||||
friend bool operator==(const value & l, const value & r);
|
||||
friend bool operator!=(const value & l, const value & r);
|
||||
friend bool operator<=(const value & l, const value & r);
|
||||
friend bool operator>=(const value & l, const value & r);
|
||||
friend bool operator< (const value & l, const value & r);
|
||||
friend bool operator> (const value & l, const value & r);
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const value& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, value& p );
|
||||
|
||||
value_iterator begin() const;
|
||||
value_iterator end() const;
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
|
||||
bool operator==(const value_view &, const value_view);
|
||||
bool operator!=(const value_view &, const value_view);
|
||||
bool operator<=(const value_view &, const value_view);
|
||||
bool operator< (const value_view &, const value_view);
|
||||
bool operator> (const value_view &, const value_view);
|
||||
bool operator>=(const value_view &, const value_view);
|
||||
|
||||
struct key_value_pair
|
||||
{
|
||||
using value_type = char_type;
|
||||
using traits_type = std::char_traits<char_type>;
|
||||
using string_type = std::basic_string<char_type>;
|
||||
using string_view_type = basic_cstring_ref<char_type>;
|
||||
|
||||
key_value_pair()l
|
||||
key_value_pair( const key_value_pair& p ) = default;
|
||||
key_value_pair( key_value_pair&& p ) noexcept = default;
|
||||
key_value_pair(key_view key, value_view value);
|
||||
|
||||
key_value_pair(key_view key, std::initializer_list<basic_string_view<char_type>> values);
|
||||
key_value_pair( const string_type& source );
|
||||
key_value_pair( string_type&& source );
|
||||
key_value_pair( const value_type * raw );
|
||||
key_value_pair( value_type * raw );
|
||||
|
||||
explicit key_value_pair(key_value_pair_view kv) : value_(kv.c_str()) {}
|
||||
|
||||
template< class Source >
|
||||
key_value_pair( const Source& source);
|
||||
|
||||
template< typename Key,
|
||||
typename Value >
|
||||
key_value_pair(
|
||||
const std::pair<Key, Value> & kv);
|
||||
|
||||
key_value_pair(const typename conditional<is_same<value_type, char>::value, wchar_t, char>::type * raw);
|
||||
|
||||
template< class InputIt , typename std::iterator_traits<InputIt>::iterator_category>
|
||||
key_value_pair( InputIt first, InputIt last );
|
||||
|
||||
~key_value_pair() = default;
|
||||
|
||||
key_value_pair& operator=( const key_value_pair& p ) = default;
|
||||
key_value_pair& operator=( key_value_pair&& p );
|
||||
key_value_pair& operator=( string_type&& source );
|
||||
template< class Source >
|
||||
key_value_pair& operator=( const Source& source );
|
||||
|
||||
key_value_pair& assign( string_type&& source );
|
||||
|
||||
template< class Source >
|
||||
key_value_pair& assign( const Source& source );
|
||||
|
||||
|
||||
template< class InputIt >
|
||||
key_value_pair& assign( InputIt first, InputIt last );
|
||||
|
||||
void clear();
|
||||
|
||||
void swap( key_value_pair& other ) noexcept;
|
||||
|
||||
const value_type* c_str() const noexcept;
|
||||
const string_type& native() const noexcept;
|
||||
string_view_type native_view() const noexcept;
|
||||
|
||||
operator string_type() const;
|
||||
operator string_view_type() const;
|
||||
operator typename string_view_type::string_view_type() const;
|
||||
operator key_value_pair_view() const;
|
||||
|
||||
int compare( const key_value_pair& p ) const noexcept;
|
||||
int compare( const string_type& str ) const;
|
||||
int compare( string_view_type str ) const;
|
||||
int compare( const value_type* s ) const;
|
||||
|
||||
template< class CharT, class Traits = std::char_traits<CharT>, class Alloc = std::allocator<CharT> >
|
||||
std::basic_string<CharT,Traits,Alloc>
|
||||
basic_string( const Alloc& alloc = Alloc() ) const;
|
||||
std::string string() const {return basic_string<char>();}
|
||||
std::wstring wstring() const {return basic_string<wchar_t>();}
|
||||
|
||||
const string_type & native_string() const;
|
||||
friend bool operator==(const key_value_pair & l, const key_value_pair & r);
|
||||
friend bool operator!=(const key_value_pair & l, const key_value_pair & r);
|
||||
friend bool operator<=(const key_value_pair & l, const key_value_pair & r);
|
||||
friend bool operator>=(const key_value_pair & l, const key_value_pair & r);
|
||||
friend bool operator< (const key_value_pair & l, const key_value_pair & r);
|
||||
friend bool operator> (const key_value_pair & l, const key_value_pair & r);
|
||||
|
||||
bool empty() const;
|
||||
|
||||
struct key_view key() const;
|
||||
struct value_view value() const;
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_ostream<CharT,Traits>&
|
||||
operator<<( std::basic_ostream<CharT,Traits>& os, const key_value_pair& p );
|
||||
|
||||
template< class CharT, class Traits >
|
||||
friend std::basic_istream<CharT,Traits>&
|
||||
operator>>( std::basic_istream<CharT,Traits>& is, key_value_pair& p );
|
||||
|
||||
const value_type * data() const;
|
||||
std::size_t size() const;
|
||||
|
||||
template<std::size_t Idx>
|
||||
inline auto get() const -> typename conditional<Idx == 0u,environment::key_view, environment::value_view>::type;
|
||||
};
|
||||
|
||||
bool operator==(const key_value_pair_view &, const key_value_pair_view);
|
||||
bool operator!=(const key_value_pair_view &, const key_value_pair_view);
|
||||
bool operator<=(const key_value_pair_view &, const key_value_pair_view);
|
||||
bool operator< (const key_value_pair_view &, const key_value_pair_view);
|
||||
bool operator> (const key_value_pair_view &, const key_value_pair_view);
|
||||
bool operator>=(const key_value_pair_view &, const key_value_pair_view);
|
||||
|
||||
|
||||
// Allow tuple-likg getters & structured bindings.
|
||||
template<>
|
||||
key_view key_value_pair::get<0u>() const;
|
||||
|
||||
template<>
|
||||
value_view key_value_pair::get<1u>() const;
|
||||
|
||||
// A view object for the current environment of this process.
|
||||
/*
|
||||
* The view might (windows) or might not (posix) be owning;
|
||||
* if it owns it will deallocate the on destruction, like a unique_ptr.
|
||||
*
|
||||
* Note that accessing the environment in this way is not thread-safe.
|
||||
*
|
||||
* @code
|
||||
*
|
||||
* void dump_my_env(current_view env = current())
|
||||
* {
|
||||
* for (auto & [k, v] : env)
|
||||
* std::cout << k.string() << " = " << v.string() << std::endl;
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct current_view
|
||||
{
|
||||
using native_handle_type = environment::native_handle_type;
|
||||
using value_type = key_value_pair_view;
|
||||
|
||||
current_view() = default;
|
||||
current_view(current_view && nt) = default;
|
||||
|
||||
native_handle_type native_handle() { return handle_.get(); }
|
||||
|
||||
struct iterator
|
||||
{
|
||||
using value_type = key_value_pair_view;
|
||||
using difference_type = int;
|
||||
using reference = key_value_pair_view;
|
||||
using pointer = key_value_pair_view;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
iterator() = default;
|
||||
iterator(const iterator & ) = default;
|
||||
iterator(const native_iterator &native_handle) : iterator_(native_handle) {}
|
||||
|
||||
iterator & operator++()
|
||||
{
|
||||
iterator_ = detail::next(iterator_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
auto last = *this;
|
||||
iterator_ = detail::next(iterator_);
|
||||
return last;
|
||||
}
|
||||
key_value_pair_view operator*() const
|
||||
{
|
||||
return detail::dereference(iterator_);
|
||||
}
|
||||
|
||||
friend bool operator==(const iterator & l, const iterator & r) {return l.iterator_ == r.iterator_;}
|
||||
friend bool operator!=(const iterator & l, const iterator & r) {return l.iterator_ != r.iterator_;}
|
||||
|
||||
private:
|
||||
environment::native_iterator iterator_;
|
||||
};
|
||||
|
||||
iterator begin() const {return iterator(handle_.get());}
|
||||
iterator end() const {return iterator(detail::find_end(handle_.get()));}
|
||||
|
||||
private:
|
||||
|
||||
std::unique_ptr<typename remove_pointer<native_handle_type>::type,
|
||||
detail::native_handle_deleter> handle_{environment::detail::load_native_handle()};
|
||||
};
|
||||
|
||||
// Obtain a handle to the current environment
|
||||
inline current_view current() {return current_view();}
|
||||
|
||||
// Find the home folder in an environment-like type.
|
||||
/*
|
||||
* @param env The environment to search. Defaults to the current environment of this process
|
||||
*
|
||||
* The environment type passed in must be a range with value T that fulfills the following requirements:
|
||||
*
|
||||
* For `T value`
|
||||
*
|
||||
* - std::get<0>(value) must return a type comparable to `key_view`.
|
||||
* - std::get<1>(value) must return a type convertible to filesystem::path.
|
||||
*
|
||||
* @return A filesystem::path to the home directory or an empty path if it cannot be found.
|
||||
*
|
||||
*/
|
||||
template<typename Environment = current_view>
|
||||
inline filesystem::path home(Environment && env = current());
|
||||
|
||||
// Find the executable `name` in an environment-like type.
|
||||
template<typename Environment = current_view>
|
||||
filesystem::path find_executable(BOOST_PROCESS_V2_NAMESPACE::filesystem::path name,
|
||||
Environment && env = current());
|
||||
|
||||
// Get an environment variable from the current process.
|
||||
value get(const key & k, error_code & ec);
|
||||
value get(const key & k);
|
||||
value get(basic_cstring_ref<char_type, key_char_traits<char_type>> k, error_code & ec);
|
||||
value get(basic_cstring_ref<char_type, key_char_traits<char_type>> k);
|
||||
value get(const char_type * c, error_code & ec);
|
||||
value get(const char_type * c);
|
||||
|
||||
// Set an environment variable for the current process.
|
||||
void set(const key & k, value_view vw, error_code & ec);
|
||||
void set(const key & k, value_view vw);
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, value_view vw, error_code & ec);
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, value_view vw);
|
||||
void set(const char_type * k, value_view vw, error_code & ec);
|
||||
void set(const char_type * k, value_view vw);
|
||||
template<typename Char>
|
||||
void set(const key & k, const Char * vw, error_code & ec);
|
||||
template<typename Char>
|
||||
void set(const key & k, const Char * vw);
|
||||
template<typename Char>
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, const Char * vw, error_code & ec);
|
||||
template<typename Char>
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> k, const Char * vw);
|
||||
template<typename Char>
|
||||
void set(const char_type * k, const Char * vw, error_code & ec);
|
||||
template<typename Char>
|
||||
void set(const char_type * k, const Char * vw);
|
||||
|
||||
// Remove an environment variable from the current process.
|
||||
void unset(const key & k, error_code & ec);
|
||||
void unset(const key & k);
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> k, error_code & ec);
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> k);
|
||||
void unset(const char_type * c, error_code & ec);
|
||||
void unset(const char_type * c);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
=== `process_environment`
|
||||
|
||||
In order to set the environment of a child process, `process_environment` can be used.
|
||||
|
||||
|
||||
|
||||
[source, cpp]
|
||||
.This will set the environment in a subprocess:
|
||||
----
|
||||
process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}};
|
||||
----
|
||||
|
||||
The environment initializer will persist it's state, so that it can
|
||||
be used multiple times. Do however note the the Operating System is
|
||||
allowed to modify the internal state.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
auto exe = find_executable("printenv");
|
||||
process_environment env = {"FOO=BAR", "BAR=FOO"};
|
||||
|
||||
process proc1(executor, exe, {"FOO"}, env);
|
||||
process proc2(executor, exe, {"BAR"}, env);
|
||||
----
|
||||
@@ -1,36 +0,0 @@
|
||||
== `error.hpp`
|
||||
[#error]
|
||||
|
||||
The error header provides two error categories:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// Errors used for utf8 <-> UCS-2 conversions.
|
||||
enum utf8_conv_error
|
||||
{
|
||||
insufficient_buffer = 1,
|
||||
invalid_character,
|
||||
};
|
||||
|
||||
extern const error_category& get_utf8_category();
|
||||
static const error_category& utf8_category = get_utf8_category();
|
||||
|
||||
extern const error_category& get_exit_code_category();
|
||||
|
||||
/// An error category that can be used to interpret exit codes of subprocesses.
|
||||
static const error_category& exit_code_category = get_exit_code_category();
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
The `get_exit_code_category` can be used as follows:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
void run_my_process(filesystem::path pt, error_code & ec)
|
||||
{
|
||||
process proc(pt, {});
|
||||
proc.wait();
|
||||
ec.assign(proc.native_exit_code(), error::get_exit_code_category());
|
||||
}
|
||||
----
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
== `execute.hpp`
|
||||
[#execute]
|
||||
|
||||
The execute header provides two error categories:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
// Run a process and wait for it to complete.
|
||||
template<typename Executor> int execute(basic_process<Executor> proc);
|
||||
template<typename Executor> int execute(basic_process<Executor> proc, error_code & ec)
|
||||
|
||||
// Execute a process asynchronously
|
||||
template<typename Executor = net::any_io_executor,
|
||||
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
|
||||
WaitHandler = net::default_completion_token_t<Executor>>
|
||||
auto async_execute(basic_process<Executor> proc,
|
||||
WaitHandler && handler = net::default_completion_token_t<Executor>());
|
||||
----
|
||||
|
||||
The `async_execute` function asynchronously for a process to complete.
|
||||
|
||||
Cancelling the execution will signal the child process to exit
|
||||
with the following interpretations:
|
||||
|
||||
- `cancellation_type::total` -> interrupt
|
||||
- `cancellation_type::partial` -> request_exit
|
||||
- `cancellation_type::terminal` -> terminate
|
||||
|
||||
It is to note that `async_execute` will use the lowest selected cancellation
|
||||
type. A subprocess might ignore anything not terminal.
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
== `exit_code.hpp`
|
||||
[#exit_code]
|
||||
|
||||
The exit code header provides portable handles for exit codes.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// The native exit-code type, usually an integral value
|
||||
/* The OS may have a value different from `int` to represent
|
||||
* the exit codes of subprocesses. It might also
|
||||
* contain additional information.
|
||||
*/
|
||||
typedef implementation_defined native_exit_code_type;
|
||||
|
||||
|
||||
// Check if the native exit code indicates the process is still running
|
||||
bool process_is_running(native_exit_code_type code);
|
||||
|
||||
// Obtain the portable part of the exit code, i.e. what the subprocess has returned from main.
|
||||
int evaluate_exit_code(native_exit_code_type code);
|
||||
|
||||
// Helper to subsume an exit-code into an error_code if there's no actual error isn't set.
|
||||
error_code check_exit_code(
|
||||
error_code &ec, native_exit_code_type native_code,
|
||||
const error_category & category = error::get_exit_code_category());
|
||||
----
|
||||
|
||||
|
||||
The `check_exit_code` can be used like this:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
process proc{co_await this_coro::executor, "exit", {"1"}};
|
||||
|
||||
co_await proc.async_wait(
|
||||
asio::deferred(
|
||||
[&proc](error_code ec, int)
|
||||
{
|
||||
return asio::deferred.values(
|
||||
check_exit_code(ec, proc.native_exit_code())
|
||||
);
|
||||
----
|
||||
@@ -1,46 +0,0 @@
|
||||
== `ext`
|
||||
|
||||
The headers in `process/ext` provides features to obtain information about third part processes.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// Get the cmd line used to launche the process
|
||||
template<typename Executor>
|
||||
shell cmd(basic_process_handle<Executor> & handle, error_code & ec);
|
||||
template<typename Executor>
|
||||
shell cmd(basic_process_handle<Executor> & handle);
|
||||
shell cmd(pid_type pid, error_code & ec);
|
||||
shell cmd(pid_type pid);
|
||||
|
||||
|
||||
// Get the current working directory of the process.
|
||||
template<typename Executor>
|
||||
filesystem::path cwd(basic_process_handle<Executor> & handle, error_code & ec);
|
||||
template<typename Executor>
|
||||
filesystem::path cwd(basic_process_handle<Executor> & handle)
|
||||
filesystem::path cwd(pid_type pid, error_code & ec);
|
||||
filesystem::path cwd(pid_type pid);
|
||||
|
||||
|
||||
// Get the current environment of the process.
|
||||
template<typename Executor>
|
||||
env_view cwd(basic_process_handle<Executor> & handle, error_code & ec);
|
||||
template<typename Executor>
|
||||
env_view cwd(basic_process_handle<Executor> & handle)
|
||||
env_view env(pid_type pid, error_code & ec);
|
||||
env_view env(pid_type pid);
|
||||
|
||||
|
||||
// Get the executable of the process.
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle, error_code & ec);
|
||||
template<typename Executor>
|
||||
filesystem::path exe(basic_process_handle<Executor> & handle)
|
||||
filesystem::path exe(pid_type pid, error_code & ec);
|
||||
filesystem::path exe(pid_type pid);
|
||||
----
|
||||
|
||||
WARNING: The function may fail with "operation_not_supported" on some niche platforms.
|
||||
|
||||
NOTE: On windows overloads taking a `HANDLE` are also available.
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
== `pid.hpp`
|
||||
[#pid]
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
//An integral type representing a process id.
|
||||
typedef implementation_defined pid_type;
|
||||
|
||||
// Get the process id of the current process.
|
||||
pid_type current_pid();
|
||||
|
||||
// List all available pids.
|
||||
std::vector<pid_type> all_pids(boost::system::error_code & ec);
|
||||
std::vector<pid_type> all_pids();
|
||||
|
||||
// return parent pid of pid.
|
||||
pid_type parent_pid(pid_type pid, boost::system::error_code & ec);
|
||||
pid_type parent_pid(pid_type pid);
|
||||
|
||||
// return child pids of pid.
|
||||
std::vector<pid_type> child_pids(pid_type pid, boost::system::error_code & ec);
|
||||
std::vector<pid_type> child_pids(pid_type pid);
|
||||
----
|
||||
@@ -1,163 +0,0 @@
|
||||
== `popen.hpp`
|
||||
[#popen]
|
||||
|
||||
`popen` is a class that launches a process and connect stdin & stderr to pipes.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
popen proc(executor, find_executable("addr2line"), {argv[0]});
|
||||
asio::write(proc, asio::buffer("main\n"));
|
||||
std::string line;
|
||||
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
|
||||
----
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// A subprocess with automatically assigned pipes.
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_popen : basic_process<Executor>
|
||||
{
|
||||
// The executor of the process
|
||||
using executor_type = Executor;
|
||||
|
||||
// Rebinds the popen type to another executor.
|
||||
template <typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
// The pipe type when rebound to the specified executor.
|
||||
typedef basic_popen<Executor1> other;
|
||||
};
|
||||
|
||||
// Move construct a popen
|
||||
basic_popen(basic_popen &&) = default;
|
||||
// Move assign a popen
|
||||
basic_popen& operator=(basic_popen &&) = default;
|
||||
|
||||
// Move construct a popen and change the executor type.
|
||||
template<typename Executor1>
|
||||
basic_popen(basic_popen<Executor1>&& lhs)
|
||||
: basic_process<Executor>(std::move(lhs)),
|
||||
stdin_(std::move(lhs.stdin_)), stdout_(std::move(lhs.stdout_))
|
||||
{
|
||||
}
|
||||
|
||||
// Create a closed process handle
|
||||
explicit basic_popen(executor_type exec);
|
||||
|
||||
// Create a closed process handle
|
||||
template <typename ExecutionContext>
|
||||
explicit basic_popen(ExecutionContext & context);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ... Inits>
|
||||
explicit basic_popen(
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ExecutionContext, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
ExecutionContext & context,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ExecutionContext, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
ExecutionContext & context,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
ExecutionContext & context,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default process launcher.
|
||||
template<typename Launcher, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
explicit basic_popen(
|
||||
Launcher && launcher,
|
||||
ExecutionContext & context,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// The type used for stdin on the parent process side.
|
||||
using stdin_type = net::basic_writable_pipe<Executor>;
|
||||
// The type used for stdout on the parent process side.
|
||||
using stdout_type = net::basic_readable_pipe<Executor>;
|
||||
|
||||
// Get the stdin pipe.
|
||||
|
||||
// Get the stdout pipe.
|
||||
|
||||
// Get the stdin pipe.
|
||||
stdin_type & get_stdin();
|
||||
const stdin_type & get_stdin() const;
|
||||
// Get the stdout pipe.
|
||||
stdout_type & get_stdout();
|
||||
const stdout_type & get_stdout() const;
|
||||
|
||||
// Write some data to the stdin pipe.
|
||||
template <typename ConstBufferSequence>
|
||||
std::size_t write_some(const ConstBufferSequence& buffers);
|
||||
template <typename ConstBufferSequence>
|
||||
std::size_t write_some(const ConstBufferSequence& buffers,
|
||||
boost::system::error_code& ec);
|
||||
|
||||
// Start an asynchronous write.
|
||||
template <typename ConstBufferSequence,
|
||||
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t))
|
||||
WriteToken = net::default_completion_token_t<executor_type>>
|
||||
auto async_write_some(const ConstBufferSequence& buffers,
|
||||
WriteToken && token = net::default_completion_token_t<executor_type>());
|
||||
|
||||
// Read some data from the stdout pipe.
|
||||
template <typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence& buffers);
|
||||
template <typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence& buffers,
|
||||
boost::system::error_code& ec)
|
||||
|
||||
// Start an asynchronous read. template <typename MutableBufferSequence,
|
||||
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t))
|
||||
ReadToken = net::default_completion_token_t<executor_type>>
|
||||
auto async_read_some(const MutableBufferSequence& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(ReadToken) token
|
||||
= net::default_completion_token_t<executor_type>());
|
||||
};
|
||||
|
||||
// A popen object with the default executor.
|
||||
using popen = basic_popen<>;
|
||||
|
||||
----
|
||||
@@ -1,70 +0,0 @@
|
||||
== `posix/bind_fd.hpp`
|
||||
|
||||
`bind_fd` is a utility class to bind a file descriptor to an explicit file descriptor for the child process.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
struct bind_fd
|
||||
{
|
||||
// Inherit file descriptor with the same value.
|
||||
/*
|
||||
* This will pass descriptor 42 as 42 to the child process:
|
||||
* @code
|
||||
* process p{"test", {}, posix::bind_fd(42)};
|
||||
* @endcode
|
||||
*/
|
||||
bind_fd(int target);
|
||||
|
||||
// Inherit an asio io-object as a given file descriptor to the child process.
|
||||
/*
|
||||
* This will pass the tcp::socket, as 42 to the child process:
|
||||
* @code
|
||||
* extern tcp::socket sock;
|
||||
* process p{"test", {}, posix::bind_fd(42, sock)};
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
template<typename Stream>
|
||||
bind_fd(int target, Stream && str);
|
||||
|
||||
// Inherit a `FILE` as a given file descriptor to the child process.
|
||||
/* This will pass the given `FILE*`, as 42 to the child process:
|
||||
|
||||
process p{"test", {}, posix::bind_fd(42, stderr)};
|
||||
|
||||
*/
|
||||
bind_fd(int target, FILE * f);
|
||||
|
||||
// Inherit a file descriptor with as a different value.
|
||||
/* This will pass 24 as 42 to the child process:
|
||||
|
||||
process p{"test", {}, posix::bind_fd(42, 24)};
|
||||
|
||||
*/
|
||||
bind_fd(int target, int fd):
|
||||
|
||||
// Inherit a null device as a set descriptor.
|
||||
/* This will a null device as 42 to the child process:
|
||||
|
||||
process p{"test", {}, posix::bind_fd(42, nullptr)};
|
||||
|
||||
*/
|
||||
bind_fd(int target, std::nullptr_t);
|
||||
|
||||
// Inherit a newly opened-file as a set descriptor.
|
||||
/* This will pass a descriptor to "extra-output.txt" as 42 to the child process:
|
||||
|
||||
process p{"test", {}, posix::bind_fd(42, "extra-output.txt")};
|
||||
|
||||
*/
|
||||
bind_fd(int target, const filesystem::path & pth, int flags = O_RDWR | O_CREAT);
|
||||
|
||||
};
|
||||
----
|
||||
|
||||
Using `bind_fd` can be used to inherit file descriptors explicitly, because no unused one will be.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
----
|
||||
@@ -1,174 +0,0 @@
|
||||
== `process.hpp`
|
||||
[#process]
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// A class managing a subprocess
|
||||
/* A `basic_process` object manages a subprocess; it tracks the status and exit-code,
|
||||
* and will terminate the process on destruction if `detach` was not called.
|
||||
*/
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process
|
||||
{
|
||||
// The executor of the process
|
||||
using executor_type = Executor;
|
||||
// Get the executor of the process
|
||||
executor_type get_executor() {return process_handle_.get_executor();}
|
||||
|
||||
// The non-closing handle type
|
||||
using handle_type = basic_process_handle<executor_type>;
|
||||
|
||||
// Get the underlying non-closing handle
|
||||
handle_type & handle() { return process_handle_; }
|
||||
|
||||
// Get the underlying non-closing handle
|
||||
const handle_type & handle() const { return process_handle_; }
|
||||
|
||||
// Provides access to underlying operating system facilities
|
||||
using native_handle_type = typename handle_type::native_handle_type;
|
||||
|
||||
// Rebinds the process_handle to another executor.
|
||||
template <typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
// The socket type when rebound to the specified executor.
|
||||
typedef basic_process<Executor1> other;
|
||||
};
|
||||
|
||||
/** An empty process is similar to a default constructed thread. It holds an empty
|
||||
handle and is a place holder for a process that is to be launched later. */
|
||||
basic_process() = default;
|
||||
|
||||
basic_process(const basic_process&) = delete;
|
||||
basic_process& operator=(const basic_process&) = delete;
|
||||
|
||||
// Move construct the process. It will be detached from `lhs`.
|
||||
basic_process(basic_process&& lhs) = default;
|
||||
|
||||
// Move assign a process. It will be detached from `lhs`.
|
||||
basic_process& operator=(basic_process&& lhs) = default;
|
||||
|
||||
// Move construct and rebind the executor.
|
||||
template<typename Executor1>
|
||||
basic_process(basic_process<Executor1>&& lhs);
|
||||
|
||||
// Construct a child from a property list and launch it using the default launcher..
|
||||
template<typename ... Inits>
|
||||
explicit basic_process(
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default launcher..
|
||||
template<typename Args, typename ... Inits>
|
||||
explicit basic_process(
|
||||
executor_type executor,
|
||||
const filesystem::path& exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// Construct a child from a property list and launch it using the default launcher..
|
||||
template<typename ExecutionContext, typename ... Inits>
|
||||
explicit basic_process(
|
||||
ExecutionContext & context,
|
||||
const filesystem::path& exe,
|
||||
std::initializer_list<string_view> args,
|
||||
Inits&&... inits);
|
||||
// Construct a child from a property list and launch it using the default launcher.
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
explicit basic_process(
|
||||
ExecutionContext & context,
|
||||
const filesystem::path&>::type exe,
|
||||
Args&& args, Inits&&... inits);
|
||||
|
||||
// Attach to an existing process
|
||||
explicit basic_process(executor_type exec, pid_type pid);
|
||||
|
||||
// Attach to an existing process and the internal handle
|
||||
explicit basic_process(executor_type exec, pid_type pid, native_handle_type native_handle);
|
||||
|
||||
// Create an invalid handle
|
||||
explicit basic_process(executor_type exec);
|
||||
|
||||
// Attach to an existing process
|
||||
template <typename ExecutionContext>
|
||||
explicit basic_process(ExecutionContext & context, pid_type pid);
|
||||
|
||||
// Attach to an existing process and the internal handle
|
||||
template <typename ExecutionContext>
|
||||
explicit basic_process(ExecutionContext & context, pid_type pid, native_handle_type native_handle);
|
||||
|
||||
// Create an invalid handle
|
||||
template <typename ExecutionContext>
|
||||
explicit basic_process(ExecutionContext & context);
|
||||
|
||||
|
||||
|
||||
// Destruct the handle and terminate the process if it wasn't detached.
|
||||
~basic_process();
|
||||
|
||||
// Sends the process a signal to ask for an interrupt, which the process may interpret as a shutdown.
|
||||
/** Maybe be ignored by the subprocess. */
|
||||
void interrupt(error_code & ec);
|
||||
void interrupt();
|
||||
|
||||
// Throwing @overload void interrupt()
|
||||
|
||||
|
||||
// Sends the process a signal to ask for a graceful shutdown. Maybe be ignored by the subprocess.
|
||||
void request_exit(error_code & ec);
|
||||
void request_exit();
|
||||
|
||||
// Send the process a signal requesting it to stop. This may rely on undocumented functions.
|
||||
void suspend(error_code &ec);
|
||||
void suspend();
|
||||
|
||||
|
||||
// Send the process a signal requesting it to resume. This may rely on undocumented functions.
|
||||
void resume(error_code &ec);
|
||||
void resume();
|
||||
|
||||
// Unconditionally terminates the process and stores the exit code in exit_status.
|
||||
void terminate(error_code & ec);
|
||||
void terminate();
|
||||
|
||||
// Waits for the process to exit, store the exit code internally and return it.
|
||||
int wait(error_code & ec);
|
||||
int wait();
|
||||
|
||||
// Detach the process.
|
||||
handle_type detach();
|
||||
// Get the native
|
||||
native_handle_type native_handle() {return process_handle_.native_handle(); }
|
||||
|
||||
// Return the evaluated exit_code.
|
||||
int exit_code() cons;
|
||||
|
||||
// Get the id of the process;
|
||||
pid_type id() const;
|
||||
|
||||
// The native handle of the process.
|
||||
/** This might be undefined on posix systems that only support signals */
|
||||
native_exit_code_type native_exit_code() const;
|
||||
|
||||
// Checks if the current process is running.
|
||||
/* If it has already completed the exit code will be stored internally
|
||||
* and can be obtained by calling `exit_code.
|
||||
*/
|
||||
bool running();
|
||||
bool running(error_code & ec) noexcept;
|
||||
|
||||
// Check if the process is referring to an existing process.
|
||||
/** Note that this might be a process that already exited.*/
|
||||
bool is_open() const;
|
||||
|
||||
// Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.
|
||||
template <BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler && handler = net::default_completion_token_t<executor_type>());
|
||||
};
|
||||
|
||||
// Process with the default executor.
|
||||
typedef basic_process<> process;
|
||||
|
||||
----
|
||||
@@ -1,108 +0,0 @@
|
||||
== `process_handle.hpp`
|
||||
[#process_handle]
|
||||
|
||||
A process handle is an unmanaged version of a process.
|
||||
This means it does not terminate the process on destruction and
|
||||
will not keep track of the exit-code.
|
||||
|
||||
NOTE: that the exit code might be discovered early, during a call to `running`.
|
||||
Thus it can only be discovered that process has exited already.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
|
||||
template<typename Executor = net::any_io_executor>
|
||||
struct basic_process_handle
|
||||
{
|
||||
// The native handle of the process.
|
||||
/* This might be undefined on posix systems that only support signals */
|
||||
using native_handle_type = implementation_defined;
|
||||
|
||||
// The executor_type of the process_handle
|
||||
using executor_type = Executor;
|
||||
|
||||
// Getter for the executor
|
||||
executor_type get_executor();
|
||||
|
||||
// Rebinds the process_handle to another executor.
|
||||
template<typename Executor1>
|
||||
struct rebind_executor
|
||||
{
|
||||
// The socket type when rebound to the specified executor.
|
||||
typedef basic_process_handle<Executor1> other;
|
||||
};
|
||||
|
||||
|
||||
// Construct a basic_process_handle from an execution_context.
|
||||
/*
|
||||
* @tparam ExecutionContext The context must fulfill the asio::execution_context requirements
|
||||
*/
|
||||
template<typename ExecutionContext>
|
||||
basic_process_handle(ExecutionContext &context);
|
||||
|
||||
// Construct an empty process_handle from an executor.
|
||||
basic_process_handle(executor_type executor);
|
||||
|
||||
// Construct an empty process_handle from an executor and bind it to a pid.
|
||||
/* On NON-linux posix systems this call is not able to obtain a file-descriptor and will thus
|
||||
* rely on signals.
|
||||
*/
|
||||
basic_process_handle(executor_type executor, pid_type pid);
|
||||
|
||||
// Construct an empty process_handle from an executor and bind it to a pid and the native-handle
|
||||
/* On some non-linux posix systems this overload is not present.
|
||||
*/
|
||||
basic_process_handle(executor_type executor, pid_type pid, native_handle_type process_handle);
|
||||
|
||||
// Move construct and rebind the executor.
|
||||
template<typename Executor1>
|
||||
basic_process_handle(basic_process_handle<Executor1> &&handle);
|
||||
|
||||
// Get the id of the process
|
||||
pid_type id() const
|
||||
{ return pid_; }
|
||||
|
||||
// Terminate the process if it's still running and ignore the result
|
||||
void terminate_if_running(error_code &);
|
||||
|
||||
// Throwing @overload void terminate_if_running(error_code & ec;
|
||||
void terminate_if_running();
|
||||
// wait for the process to exit and store the exit code in exit_status.
|
||||
void wait(native_exit_code_type &exit_status, error_code &ec);
|
||||
// Throwing @overload wait(native_exit_code_type &exit_code, error_code & ec)
|
||||
void wait(native_exit_code_type &exit_status);
|
||||
|
||||
// Sends the process a signal to ask for an interrupt, which the process may interpret as a shutdown.
|
||||
/* Maybe be ignored by the subprocess. */
|
||||
void interrupt(error_code &ec);
|
||||
|
||||
// Throwing @overload void interrupt()
|
||||
void interrupt();
|
||||
|
||||
// Sends the process a signal to ask for a graceful shutdown. Maybe be ignored by the subprocess.
|
||||
void request_exit(error_code &ec);
|
||||
|
||||
// Throwing @overload void request_exit(error_code & ec)
|
||||
void request_exit()
|
||||
|
||||
// Unconditionally terminates the process and stores the exit code in exit_status.
|
||||
void terminate(native_exit_code_type &exit_status, error_code &ec);\
|
||||
// Throwing @overload void terminate(native_exit_code_type &exit_code, error_code & ec)
|
||||
void terminate(native_exit_code_type &exit_status);/
|
||||
|
||||
// Checks if the current process is running.
|
||||
/*If it has already completed, it assigns the exit code to `exit_code`.
|
||||
*/
|
||||
bool running(native_exit_code_type &exit_code, error_code &ec);
|
||||
// Throwing @overload bool running(native_exit_code_type &exit_code, error_code & ec)
|
||||
bool running(native_exit_code_type &exit_code);
|
||||
|
||||
// Check if the process handle is referring to an existing process.
|
||||
bool is_open() const;
|
||||
|
||||
// Asynchronously wait for the process to exit and deliver the native exit-code in the completion handler.
|
||||
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
|
||||
WaitHandler = net::default_completion_token_t<executor_type>>
|
||||
auto async_wait(WaitHandler &&handler = net::default_completion_token_t<executor_type>());
|
||||
};
|
||||
----
|
||||
@@ -1,57 +0,0 @@
|
||||
== `shell.hpp`
|
||||
[#shell]
|
||||
|
||||
This utility class parses command lines into tokens
|
||||
and allows users to execute processes based on textual inputs.
|
||||
|
||||
In v1, this was possible directly when starting a process,
|
||||
but has been removed based on the security risks associated with this.
|
||||
|
||||
By making the shell parsing explicitly, it encourages
|
||||
a user to run a sanity check on the executable before launching it.
|
||||
|
||||
.Example
|
||||
[source,cpp]
|
||||
----
|
||||
asio::io_context ctx;
|
||||
|
||||
auto cmd = shell("my-app --help");
|
||||
auto exe = cmd.exe();
|
||||
check_if_malicious(exe);
|
||||
|
||||
process proc{ctx, exe, cmd.args()};
|
||||
|
||||
----
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
/// Utility to parse commands
|
||||
struct shell
|
||||
{
|
||||
shell() = default;
|
||||
template<typename Char, typename Traits>
|
||||
shell(basic_string_view<Char, Traits> input);
|
||||
|
||||
shell(basic_cstring_ref<char_type> input);
|
||||
shell(const shell &) = delete;
|
||||
shell(shell && lhs) noexcept;
|
||||
shell& operator=(const shell &) = delete;
|
||||
shell& operator=(shell && lhs) noexcept;
|
||||
|
||||
|
||||
// the length of the parsed shell, including the executable
|
||||
int argc() const ;
|
||||
char_type** argv() const;
|
||||
|
||||
char_type** begin() const;
|
||||
char_type** end() const;
|
||||
|
||||
bool empty() const;
|
||||
std::size_t size() const;
|
||||
|
||||
// Native representation of the arguments to be used - excluding the executable
|
||||
args_type args() const;
|
||||
template<typename Environment = environment::current_view>
|
||||
filesystem::path exe(Environment && env = environment::current()) const;
|
||||
};
|
||||
----
|
||||
@@ -1,16 +0,0 @@
|
||||
== `start_dir.hpp`
|
||||
[#start_dir]
|
||||
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
/// Initializer for the starting directory of a subprocess to be launched.
|
||||
struct process_start_dir
|
||||
{
|
||||
filesystem::path start_dir;
|
||||
|
||||
process_start_dir(filesystem::path start_dir);
|
||||
{
|
||||
}
|
||||
};
|
||||
----
|
||||
@@ -1,55 +0,0 @@
|
||||
== `stdio.hpp`
|
||||
[#stdio]
|
||||
|
||||
The initializer for the stdio of a subprocess
|
||||
The subprocess stdio initializer has three members:
|
||||
|
||||
- in for stdin
|
||||
- out for stdout
|
||||
- err for stderr
|
||||
|
||||
If the initializer is present all three will be set for the subprocess.
|
||||
By default they will inherit the stdio handles from the parent process.
|
||||
This means that this will forward stdio to the subprocess:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
asio::io_context ctx;
|
||||
v2::process proc(ctx, "/bin/bash", {}, v2::process_stdio{});
|
||||
----
|
||||
|
||||
No constructors are provided in order to support designated initializers
|
||||
in later version of C++.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
asio::io_context ctx;
|
||||
|
||||
/// C++17
|
||||
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{.stderr=nullptr});
|
||||
/// C++11 & C++14
|
||||
v2::process proc17(ctx, "/bin/bash", {}, v2::process_stdio{ {}, {}, nullptr});
|
||||
----
|
||||
|
||||
Valid initializers for any stdio are:
|
||||
|
||||
- `std::nullptr_t` assigning a null-device
|
||||
- `FILE*` any open file, including `stdin`, `stdout` and `stderr`
|
||||
- a filesystem::path, which will open a readable or writable depending on the direction of the stream
|
||||
- `native_handle` any native file handle (`HANDLE` on windows) or file descriptor (`int` on posix)
|
||||
- any io-object with a .native_handle() function that is compatible with the above. E.g. a asio::ip::tcp::socket
|
||||
- an asio::basic_writeable_pipe for stdin or asio::basic_readable_pipe for stderr/stdout.
|
||||
|
||||
|
||||
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
/// The initializer for the stdio of a subprocess
|
||||
struct process_stdio
|
||||
{
|
||||
__implementation_defined__ in;
|
||||
__implementation_defined__ out;
|
||||
__implementation_defined__ err;
|
||||
};
|
||||
----
|
||||
@@ -1,27 +0,0 @@
|
||||
== `windows/creation_flags.hpp`
|
||||
|
||||
Creation flags allows explicitly setting `dwFlags`
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
// An initializer to add to the dwFlags in the startup-info
|
||||
template<DWORD Flags>
|
||||
struct process_creation_flags;
|
||||
|
||||
// A flag to create a new process group. Necessary to allow interrupts for the subprocess.
|
||||
constexpr static process_creation_flags<CREATE_NEW_PROCESS_GROUP> create_new_process_group;
|
||||
|
||||
// Breakaway from the current job object.
|
||||
constexpr static process_creation_flags<CREATE_BREAKAWAY_FROM_JOB> create_breakaway_from_job;
|
||||
// Allocate a new console.
|
||||
constexpr static process_creation_flags<CREATE_NEW_CONSOLE> create_new_console;
|
||||
|
||||
----
|
||||
|
||||
|
||||
The flags can be used like this:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
process p{"C:\\not-a-virus.exe", {}, process::windows::create_new_console};
|
||||
----
|
||||
@@ -1,32 +0,0 @@
|
||||
== `windows/show_window.hpp`
|
||||
|
||||
Creation flags allows explicitly setting `wShowWindow` options
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
/// A templated initializer to set wShowWindow flags.
|
||||
template<DWORD Flags>
|
||||
struct process_show_window;
|
||||
|
||||
//Hides the window and activates another window.
|
||||
constexpr static process_show_window<SW_HIDE > show_window_hide;
|
||||
//Activates the window and displays it as a maximized window.
|
||||
constexpr static process_show_window<SW_SHOWMAXIMIZED > show_window_maximized;
|
||||
//Activates the window and displays it as a minimized window.
|
||||
constexpr static process_show_window<SW_SHOWMINIMIZED > show_window_minimized;
|
||||
//Displays the window as a minimized window. This value is similar to `minimized`, except the window is not activated.
|
||||
constexpr static process_show_window<SW_SHOWMINNOACTIVE> show_window_minimized_not_active;
|
||||
//Displays a window in its most recent size and position. This value is similar to show_normal`, except that the window is not activated.
|
||||
constexpr static process_show_window<SW_SHOWNOACTIVATE > show_window_not_active;
|
||||
//Activates and displays a window. If the window is minimized or maximized, the system restores it to its original size and position. An application should specify this flag when displaying the window for the first time.
|
||||
constexpr static process_show_window<SW_SHOWNORMAL > show_window_normal;
|
||||
|
||||
----
|
||||
|
||||
|
||||
The flags can be used like this:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
process p{"C:\\not-a-virus.exe", {}, process::windows::show_window_minimized};
|
||||
----
|
||||
@@ -1,13 +0,0 @@
|
||||
== `process_start_dir`
|
||||
|
||||
The easier initializer to use is `process_start_dir`:
|
||||
|
||||
.example/start_dir.cpp:17-20
|
||||
[source,cpp,indent=0]
|
||||
----
|
||||
include::../example/start_dir.cpp[tag=start_dir]
|
||||
----
|
||||
|
||||
This will run `ls` in the folder `/home` instead of the current folder.
|
||||
|
||||
WARNING: If your path is relative, it may fail on posix, because the directory is changed before a call to execve.
|
||||
@@ -1,65 +0,0 @@
|
||||
= stdio
|
||||
|
||||
When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process.
|
||||
The default setting is to inherit the parent process.
|
||||
|
||||
This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams.
|
||||
|
||||
== Pipes
|
||||
|
||||
asio pipes can be used for io. When using in process_stdio they will get
|
||||
automatically connected and the other side will get assigned to the child process:
|
||||
|
||||
.example/stdio.cpp:20-29
|
||||
[source,cpp,indent=0]
|
||||
----
|
||||
include::../example/stdio.cpp[tag=readable_pipe]
|
||||
----
|
||||
|
||||
readable pipes can be assigned to `out` and `err`, while writable_pipes can be assigned to `in`.
|
||||
|
||||
== `FILE*`
|
||||
|
||||
`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used:
|
||||
|
||||
.example/stdio.cpp:35-38
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/stdio.cpp[tag=file]
|
||||
----
|
||||
|
||||
== `nullptr`
|
||||
|
||||
`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows).
|
||||
This is used to ignore output or give only EOF as input.
|
||||
|
||||
.example/stdio.cpp:43-46
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/stdio.cpp[tag=null]
|
||||
----
|
||||
|
||||
== `native_handle`
|
||||
|
||||
A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows.
|
||||
Furthermore, any object that has a `native_handle` function which returns a valid type for a stdio stream.
|
||||
|
||||
E.g. a domain socket on linux.
|
||||
|
||||
.example/stdio.cpp:52-57
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/stdio.cpp[tag=native_handle]
|
||||
----
|
||||
|
||||
== popen
|
||||
|
||||
Additionally, process v2 provides a `popen` class.
|
||||
It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream.
|
||||
|
||||
.example/stdio.cpp:63-66
|
||||
[source,cpp]
|
||||
----
|
||||
include::../example/stdio.cpp[tag=popen]
|
||||
----
|
||||
|
||||
431
doc/tutorial.qbk
Normal file
431
doc/tutorial.qbk
Normal file
@@ -0,0 +1,431 @@
|
||||
[def bp::system [funcref boost::process::system bp::system]]
|
||||
[def bp::spawn [funcref boost::process::system bp::spawn]]
|
||||
[def bp::child [classref boost::process::child bp::child]]
|
||||
[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 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_exit_code [memberref boost::process::child::exit_code exit_code]]
|
||||
[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 bp::std_in [globalref boost::process::std_in bp::std_in]]
|
||||
[def bp::std_out [globalref boost::process::std_out bp::std_out]]
|
||||
[def bp::std_err [globalref boost::process::std_err bp::std_err]]
|
||||
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]]
|
||||
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
|
||||
[def bp::environment [classref boost::process::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
|
||||
|
||||
[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 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]]
|
||||
|
||||
[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__.
|
||||
|
||||
[section Starting a process]
|
||||
|
||||
We want to start a process, so let's start with a simple process. We will
|
||||
invoke the gcc compiler to compile a simple program.
|
||||
|
||||
With the standard library this looks like this.
|
||||
|
||||
```
|
||||
int result = std::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
Which we can write exactly like this in boost.process.
|
||||
|
||||
```
|
||||
namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
The first thing we can do, is to separate the command and the executable into
|
||||
two parts, so it is more readable and can be built by a function.
|
||||
|
||||
```
|
||||
int result = bp::system("g++", "main.cpp");
|
||||
```
|
||||
|
||||
With that sytax we still have "g++" hard-coded, so let's assume we get the string
|
||||
from an external source as `boost::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = "g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
Now, there is a subtle difference between the two syntaxes, i.e. passing a
|
||||
single string or passing multiple. When passing multiple string, the first string will be
|
||||
interpreted as the name of a file and the rest as arguments;
|
||||
when passing one string it will be interpreted as a command.
|
||||
|
||||
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 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,
|
||||
we can also use the [funcref boost::process::spawn spawn] function or the
|
||||
[classref boost::process::child child] class.
|
||||
|
||||
The [funcref boost::process::spawn spawn] function launches a process and
|
||||
immediately detaches so, so no handle will be returned and the process will be ignored.
|
||||
This is not what we need for compiling, but maybe we want to entertain the user,
|
||||
while compiling:
|
||||
|
||||
```
|
||||
bp::spawn("chrome", boost_org);
|
||||
```
|
||||
|
||||
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("g++", "main.cpp");
|
||||
|
||||
while (c.child_running())
|
||||
do_some_stuff();
|
||||
|
||||
c.child_wait(); //wait for the process to exit
|
||||
int result = c.child_exit_code();
|
||||
```
|
||||
|
||||
So we launch the process, by calling the child constructor. Then we check and do other
|
||||
things while the process is running and afterwards get the exit code. The call
|
||||
to child_wait is necessary, to obtain it and tell the operating system, that no
|
||||
one is waiting for the process anymore.
|
||||
|
||||
[note You can also wait for a time span or a until a time point with __wait_for__ and __wait_until__]
|
||||
|
||||
[warning If you don't call wait on a child object, it will be terminated on destruction.
|
||||
This can be avoided by calling __detach__ beforehand]
|
||||
|
||||
[endsect]
|
||||
[section:error_handling Error]
|
||||
|
||||
Until now, we have assumed that everything works out, but it is not impossible,
|
||||
that "g++" is not present. That will cause the launch of the process to fail.
|
||||
The default behaviour of all functions is to throw an
|
||||
[@http://en.cppreference.com/w/cpp/error/system_error std::system_error] on failure.
|
||||
As with many other functions in this library, passing an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code]
|
||||
will change the behaviour, so that instead of throwing an exception, the error will be a assigned to the error code.
|
||||
|
||||
```
|
||||
std::error_code ec;
|
||||
bp::system c("g++", "main.cpp", ec);
|
||||
```
|
||||
[endsect]
|
||||
[section:io Synchronous I/O]
|
||||
|
||||
In the examples given above, we have only started a program, but did not consider the output.
|
||||
The default depends on the system, but usually this will just write it to the same output as the launching process.
|
||||
If this shall be guaranteed, the streams can be explicitly forwarded like this.
|
||||
|
||||
```
|
||||
bp::system("g++", bp::std_out > stdout, bp::std_err > stderr, bp::std_in < stdin);
|
||||
```
|
||||
|
||||
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);
|
||||
```
|
||||
|
||||
Alternatively we can also easily redirect the output to a file:
|
||||
|
||||
```
|
||||
bp::system("g++", "main.cpp", bp::std_out > "gcc_out.log");
|
||||
```
|
||||
|
||||
Now, let's take a more visual example for reading data.
|
||||
[@http://pubs.opengroup.org/onlinepubs/009696699/utilities/nm.html nm] is a tool on posix,
|
||||
which reads the outline, i.e. a list of all entry points, of a binary.
|
||||
Every entry point will be put into a single line, and we will use a pipe to read it.
|
||||
At the end an empty line is appended, which we use as the indication to stop reading.
|
||||
Boost.process provides the pipestream ([classref boost::process::ipstream ipstream],
|
||||
[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to
|
||||
wrap around the [classref boost::process::pipe pipe] and provide an implementation of the
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream],
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_outline(std::string & file)
|
||||
{
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("nm", file, bp::std_out > is);
|
||||
|
||||
std::vector<std::string> data;
|
||||
std::string line;
|
||||
|
||||
while (c.child_running() && std::getline(is, line) && !line.empty())
|
||||
data.push_back(line);
|
||||
|
||||
c.child_wait();
|
||||
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
What this does is redirect the `stdout` of the process into a pipe and we read this
|
||||
synchronously.
|
||||
|
||||
[warning The pipe will cause a deadlock if you try to read after nm exited]
|
||||
[note You can do the same thing with [globalref boost::process::std_err std_err]]
|
||||
|
||||
Now we get the name from `nm` and we might want to demangle it, so we use input and output.
|
||||
`nm` has a demangle option, but for the sake of the example, we'll use
|
||||
[@https://sourceware.org/binutils/docs/binutils/c_002b_002bfilt.html c++filt] for this.
|
||||
|
||||
```
|
||||
bp::opstream in;
|
||||
bp::ipstream out;
|
||||
|
||||
bp::child c("c++filt", std_out > out, std_in < in);
|
||||
|
||||
in << "_ZN5boost7process8tutorialE" << endl;
|
||||
std::string value;
|
||||
out >> value;
|
||||
|
||||
c.child_terminate();
|
||||
```
|
||||
|
||||
Now you might want to forward output from one process to another processes input.
|
||||
|
||||
```
|
||||
std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
{
|
||||
bp::pipe p;
|
||||
bp::ipstream is;
|
||||
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the
|
||||
bp::child nm("nm", file, bp::std_out > p);
|
||||
bp::child filt("c++filt", bp::std_in < p, bp::std_out > is);
|
||||
|
||||
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.child_terminate();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now this forwards the data from `nm` to `c++filt` without your process needing to do anything.
|
||||
|
||||
[endsect]
|
||||
[section:async_io Asynchronous I/O]
|
||||
|
||||
Boost.process allows the usage of boost.asio to implement asynchronous I/O.
|
||||
If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend),
|
||||
you can use [classref boost::process::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above.
|
||||
|
||||
Now we get back to our compiling example. `nm` we might analyze it line by line,
|
||||
but the compiler output will just be put into one large buffer.
|
||||
|
||||
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
|
||||
bp::async_pipe ap(ios);
|
||||
|
||||
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){});
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
|
||||
provided we also pass a reference to an io_service.
|
||||
|
||||
```
|
||||
io_service ios;
|
||||
std::vector<char> buf;
|
||||
|
||||
child c("g++", "main.cpp", bp::std_out > asio_buffer(buf), ios);
|
||||
|
||||
ios.run();
|
||||
c.wait();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
|
||||
[memberref boost::process::child::wait wait] is needed]
|
||||
|
||||
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.
|
||||
|
||||
Now we will revisit our first example and read the compiler output asynchronously:
|
||||
|
||||
```
|
||||
boost::asio::io_service ios;
|
||||
|
||||
std::future<std::string> data;
|
||||
|
||||
child c("g++", "main.cpp", //set the input
|
||||
bp::std_in.close(),
|
||||
bp::std_out > bp::null, //so it can be written without anything
|
||||
bp::std_err > data,
|
||||
ios);
|
||||
|
||||
|
||||
ios.run(); //this will actually block until the compiler is finished
|
||||
|
||||
auto err = fut.get();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
[section:group Groups]
|
||||
|
||||
When launching several processes, processes can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modifiy the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
it will not terminate all the child processes of the child unless you use a group.
|
||||
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c1("foo", g);
|
||||
bp::child c2("bar", g);
|
||||
g.group_terminate();
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/group.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[section:env Environment]
|
||||
|
||||
This library provides access to the environment of the current process and allows
|
||||
setting it for the child process.
|
||||
|
||||
```
|
||||
//get a handle to the current environment
|
||||
auto env = boost::this_process::environment();
|
||||
//add a variable to the current environment
|
||||
env["VALUE_1"] = "foo";
|
||||
|
||||
//copy it into a environment seperate to the one of this process
|
||||
bp::environment env_ = env;
|
||||
//add a value only to the new env
|
||||
env_["VALUE_2"] = "bar";
|
||||
|
||||
//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.
|
||||
|
||||
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]
|
||||
@@ -1,81 +0,0 @@
|
||||
= Version 2
|
||||
|
||||
Boost.process V2 is an redesign of boost.process, based on previous
|
||||
design mistakes & improved system APIs.
|
||||
|
||||
The major changes are
|
||||
|
||||
* Simplified interface
|
||||
* Reliance on pidfd_open on linux
|
||||
* Full asio integration
|
||||
* Removed unreliable functionality
|
||||
* UTF8 Support
|
||||
* separate compilation
|
||||
* fd safe by default
|
||||
|
||||
Version 2 is now the defauled. In order to discourage usage of the deprecated v1, it's documentation has been removed.
|
||||
|
||||
== Simplified Interface
|
||||
|
||||
In process v1 one can define partial settings in the constructor of the process,
|
||||
which has lead to a small DSL.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"};
|
||||
----
|
||||
|
||||
While this looks fancy at first, it really does not scale well with more parameters.
|
||||
For process v2, the interfaces is simple:
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
extern std::unordered_map<std::string, std::string> my_env;
|
||||
extern asio::io_context ctx;
|
||||
process proc(ctx, "./test", {"--help"}, process_stdio{nullptr, {}, {}}, process_environment(my_env));
|
||||
----
|
||||
|
||||
Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
|
||||
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
|
||||
exe-args that can be randomly spread out.
|
||||
|
||||
|
||||
== `pidfd_open`
|
||||
|
||||
Since process v1 came out, linux has moved along and added [pidfd_open](https://man7.org/linux/man-pages/man2/pidfd_open.2.html)
|
||||
which allows users to obtain a descriptor for a process.
|
||||
This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
|
||||
Windows has provided `HANDLE`s for processes all along.
|
||||
Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting
|
||||
for processes.
|
||||
|
||||
== Full asio integration
|
||||
|
||||
Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging
|
||||
for deadlocks.
|
||||
Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and
|
||||
file-handles for the subprocess.
|
||||
|
||||
== Unreliable functionality
|
||||
|
||||
Certain parts of boost.process were not as reliable as they should've been.
|
||||
|
||||
This concerns especially the `wait_for` and `wait_until` functions on the process.
|
||||
The latter are easy to do on windows, but posix does not provide an API for this.
|
||||
Thus the wait_for used signals or fork, which was all but safe.
|
||||
Since process v2 is based on asio and thus supports cancellation,
|
||||
a wait_for can now safely be implemented with an async_wait + timeout.
|
||||
|
||||
== UTF-8
|
||||
|
||||
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere
|
||||
and uses the UTF-16 APIs.
|
||||
|
||||
== Fd safe by default
|
||||
|
||||
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
|
||||
posix systems create a problem with inheriting file handles by default.
|
||||
|
||||
Process V2 will automatically close all non-whitelisted descriptors,
|
||||
without needing any option to enable it.
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
# Copyright (c) 2022 Klemens Morgenstern
|
||||
# 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)
|
||||
|
||||
project : requirements
|
||||
<include>../../..
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<link>static
|
||||
;
|
||||
|
||||
import testing ;
|
||||
|
||||
exe intro : intro.cpp /boost//process : <boost.process.fs>boost ;
|
||||
exe intro_popen : intro_popen.cpp /boost//process : <boost.process.fs>boost ;
|
||||
exe quickstart : quickstart.cpp /boost//process : <boost.process.fs>boost ;
|
||||
exe env : env.cpp /boost//process : <boost.process.fs>boost ;
|
||||
exe start_dir : start_dir.cpp /boost//process : <boost.process.fs>boost ;
|
||||
exe stdio : stdio.cpp /boost//process : <boost.process.fs>boost ;
|
||||
compile args.cpp ;
|
||||
compile async_io.cpp ;
|
||||
compile env.cpp ;
|
||||
compile error_handling.cpp ;
|
||||
compile io.cpp ;
|
||||
compile posix.cpp : <build>no <target-os>linux:<build>yes ;
|
||||
compile start_dir.cpp ;
|
||||
compile sync_io.cpp ;
|
||||
compile terminate.cpp ;
|
||||
compile wait.cpp ;
|
||||
compile windows.cpp : <build>no <target-os>windows:<build>yes ;
|
||||
|
||||
29
example/args.cpp
Normal file
29
example/args.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
bp::child c("test.exe", "--foo", "/bar");
|
||||
|
||||
//or explicit
|
||||
|
||||
bp::child c2(
|
||||
bp::exe="test.exe",
|
||||
bp::args={"--foo", "/bar"}
|
||||
);
|
||||
|
||||
c.wait();
|
||||
c2.wait();
|
||||
}
|
||||
@@ -7,22 +7,24 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_TEST_MAIN
|
||||
#define BOOST_TEST_IGNORE_SIGCHLD
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/use_future.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/process/v1/async_system.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/array.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace bp = boost::process::v1;
|
||||
namespace bp = boost::process;
|
||||
|
||||
void fail_func()
|
||||
int main()
|
||||
{
|
||||
boost::asio::io_context ios;
|
||||
boost::asio::io_service ios;
|
||||
boost::asio::streambuf buffer;
|
||||
|
||||
bp::async_system(ios, boost::asio::use_future, "foo", bp::ignore_error);
|
||||
|
||||
bp::child c(
|
||||
"test.exe",
|
||||
bp::std_out > buffer,
|
||||
ios
|
||||
);
|
||||
|
||||
ios.run();
|
||||
}
|
||||
@@ -8,38 +8,17 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace boost::process;
|
||||
namespace asio = boost::asio;
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
{ // tag::current_env[]
|
||||
// search in the current environment
|
||||
auto exe = environment::find_executable("g++");
|
||||
bp::environment my_env = boost::this_process::environment();
|
||||
|
||||
std::unordered_map <environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
my_env["PATH"] += "/foo";
|
||||
bp::system("test.exe", my_env);
|
||||
|
||||
auto other_exe = environment::find_executable("g++", my_env);
|
||||
//end::current_env[]
|
||||
}
|
||||
|
||||
{
|
||||
// tag::subprocess_env[]
|
||||
asio::io_context ctx;
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
auto exe = environment::find_executable("g++", my_env);
|
||||
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
|
||||
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
|
||||
// end::subprocess_env[]
|
||||
}
|
||||
|
||||
bp::system("test.exe", bp::env["PATH"]+="/bar");
|
||||
}
|
||||
|
||||
24
example/error_handling.cpp
Normal file
24
example/error_handling.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
std::error_code ec;
|
||||
bp::child c1("test.exe", ec);
|
||||
|
||||
|
||||
bp::child c2("test.exe", bp::ignore_error);
|
||||
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
// Copyright (c) 2022 Klemens Morgenstern
|
||||
// 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)
|
||||
@@ -6,35 +10,18 @@
|
||||
//[intro
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace proc = boost::process;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
using namespace boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe p{ctx};
|
||||
|
||||
const auto exe = proc::environment::find_executable("gcc");
|
||||
|
||||
proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}};
|
||||
ipstream pipe_stream;
|
||||
child c("gcc.exe", "--version", std_out > pipe_stream);
|
||||
|
||||
std::string line;
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto sz = asio::read(p, asio::dynamic_buffer(line), ec);
|
||||
assert(ec == asio::error::eof);
|
||||
|
||||
std::cout << "Gcc version: '" << line << "'" << std::endl;
|
||||
while (pipe_stream && std::getline(pipe_stream, line) && !line.empty())
|
||||
std::cerr << line << std::endl;
|
||||
|
||||
c.wait();
|
||||
return c.exit_code();
|
||||
}
|
||||
//]
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2022Klemens 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)
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
//[intro
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/readable_pipe.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
namespace proc = boost::process;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
asio::io_context ctx;
|
||||
const auto exe = proc::environment::find_executable("gcc");
|
||||
proc::popen c{ctx, exe, {"--version"}};
|
||||
|
||||
std::string line;
|
||||
boost::system::error_code ec;
|
||||
|
||||
auto sz = asio::read(c, asio::dynamic_buffer(line), ec);
|
||||
assert(ec == asio::error::eof);
|
||||
|
||||
boost::ignore_unused(sz);
|
||||
|
||||
std::cout << "Gcc version: '" << line << "'" << std::endl;
|
||||
|
||||
c.wait();
|
||||
return c.exit_code();
|
||||
}
|
||||
//]
|
||||
91
example/io.cpp
Normal file
91
example/io.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
//
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::std_out > stdout, //forward
|
||||
bp::std_err.close(), //close
|
||||
bp::std_in < bp::null //null in
|
||||
);
|
||||
|
||||
boost::filesystem::path p = "input.txt";
|
||||
|
||||
bp::system(
|
||||
"test.exe",
|
||||
(bp::std_out & bp::std_err) > "output.txt", //redirect both to one file
|
||||
bp::std_in < p //read input from file
|
||||
);
|
||||
|
||||
{
|
||||
bp::opstream p1;
|
||||
bp::ipstream p2;
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::std_out > p2,
|
||||
bp::std_in < p1
|
||||
);
|
||||
p1 << "my_text";
|
||||
int i = 0;
|
||||
p2 >> i;
|
||||
|
||||
}
|
||||
{
|
||||
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_service,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in)
|
||||
{
|
||||
p1.async_close();
|
||||
p2.async_close();
|
||||
})
|
||||
);
|
||||
std::vector<char> in_buf;
|
||||
std::string value = "my_string";
|
||||
boost::asio::async_write(p1, boost::asio::buffer(value), []( const boost::system::error_code&, std::size_t){});
|
||||
boost::asio::async_read (p2, boost::asio::buffer(in_buf), []( const boost::system::error_code&, std::size_t){});
|
||||
}
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
std::vector<char> in_buf;
|
||||
std::string value = "my_string";
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::std_out > bp::buffer(in_buf),
|
||||
bp::std_in < bp::buffer(value)
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
std::future<std::vector<char>> in_buf;
|
||||
std::future<void> write_fut;
|
||||
std::string value = "my_string";
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::std_out > in_buf,
|
||||
bp::std_in < bp::buffer(value) > write_fut
|
||||
);
|
||||
|
||||
write_fut.get();
|
||||
in_buf.get();
|
||||
}
|
||||
}
|
||||
46
example/posix.cpp
Normal file
46
example/posix.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
//duplicate our pipe descriptor into literal position 4
|
||||
pipe p;
|
||||
system("test", posix::fd.bind(4, p.native_sink()) );
|
||||
|
||||
|
||||
//close file-descriptor from explicit integral value
|
||||
system("test", posix::fd.close(STDIN_FILENO));
|
||||
|
||||
//close file-descriptors from explicit integral values
|
||||
system("test", posix::fd.close({STDIN_FILENO, STDOUT_FILENO}));
|
||||
|
||||
//add custom handlers
|
||||
const char *env[2] = { 0 };
|
||||
env[0] = "LANG=de";
|
||||
system("test",
|
||||
on_setup([env](auto &e) { e.env = const_cast<char**>(env); }),
|
||||
posix::on_fork_error([](auto&)
|
||||
{ std::cerr << errno << std::endl; }),
|
||||
posix::on_exec_setup([](auto&)
|
||||
{ ::chroot("/new/root/directory/"); }),
|
||||
posix::on_exec_error([](auto&)
|
||||
{ std::ofstream ofs("log.txt"); if (ofs) ofs << errno; })
|
||||
);
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace asio = boost::asio;
|
||||
using boost::process::process;
|
||||
|
||||
|
||||
int main(int /*argv*/, char ** /*argv*/)
|
||||
{
|
||||
asio::io_context ctx;
|
||||
{
|
||||
//tag::cp[]
|
||||
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
|
||||
process proc(ctx.get_executor(), // <1>
|
||||
"/usr/bin/cp", // <2>
|
||||
{"source.txt", "target.txt"} // <3>
|
||||
); // <4>
|
||||
//end::cp[]
|
||||
}
|
||||
{
|
||||
//tag::ls[]
|
||||
process proc(ctx, "/bin/ls", {});
|
||||
assert(proc.wait() == 0);
|
||||
//end::ls[]
|
||||
}
|
||||
{
|
||||
//tag::terminate[]
|
||||
process proc(ctx, "/bin/totally-not-a-virus", {});
|
||||
proc.terminate();
|
||||
//end::terminate[]
|
||||
}
|
||||
{
|
||||
//tag::request_exit[]
|
||||
process proc(ctx, "/bin/bash", {});
|
||||
proc.request_exit();
|
||||
proc.wait();
|
||||
//end::request_exit[]
|
||||
}
|
||||
{
|
||||
//tag::interrupt[]
|
||||
process proc(ctx, "/usr/bin/addr2line", {});
|
||||
proc.interrupt();
|
||||
proc.wait();
|
||||
//end::interrupt[]
|
||||
}
|
||||
{
|
||||
//tag::execute[]
|
||||
assert(execute(process(ctx, "/bin/ls", {})) == 0);
|
||||
//end::execute[]
|
||||
}
|
||||
{
|
||||
//tag::async_execute[]
|
||||
async_execute(process(ctx, "/usr/bin/g++", {"hello_world.cpp"}))
|
||||
(asio::cancel_after(std::chrono::seconds(10), asio::cancellation_type::partial)) // <1>
|
||||
(asio::cancel_after(std::chrono::seconds(10), asio::cancellation_type::terminal)) //<2>
|
||||
(asio::detached);
|
||||
//end::async_execute[]
|
||||
ctx.run();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,15 +8,20 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace boost::process;
|
||||
namespace asio = boost::asio;
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
// tag::start_dir[]
|
||||
asio::io_context ctx;
|
||||
process ls(ctx.get_executor(), "/ls", {}, process_start_dir("/home"));
|
||||
ls.wait();
|
||||
// end::start_dir[]
|
||||
bp::system(
|
||||
"test.exe",
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
|
||||
boost::filesystem::path exe = "test.exe";
|
||||
bp::system(
|
||||
boost::filesystem::absolute(exe),
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,70 +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
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
using namespace boost::process;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
{
|
||||
//tag::readable_pipe[]
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe rp{ctx};
|
||||
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
|
||||
std::string output;
|
||||
|
||||
boost::system::error_code ec;
|
||||
asio::read(rp, asio::dynamic_buffer(output), ec);
|
||||
assert(!ec || (ec == asio::error::eof));
|
||||
proc.wait();
|
||||
//end::readable_pipe[]
|
||||
}
|
||||
|
||||
{
|
||||
//tag::file[]
|
||||
asio::io_context ctx;
|
||||
// forward both stderr & stdout to stdout of the parent process
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout});
|
||||
proc.wait();
|
||||
//end::file[]
|
||||
}
|
||||
{
|
||||
//tag::null[]
|
||||
asio::io_context ctx;
|
||||
// forward stderr to /dev/null or NUL
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr});
|
||||
proc.wait();
|
||||
//end::null[]
|
||||
}
|
||||
#if defined(BOOST_POSIX_API)
|
||||
{
|
||||
//tag::native_handle[]
|
||||
asio::io_context ctx;
|
||||
// ignore stderr
|
||||
asio::local::stream_protocol::socket sock{ctx}, other{ctx};
|
||||
asio::local::connect_pair(sock, other);
|
||||
process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr});
|
||||
proc.wait();
|
||||
//end::native_handle[]
|
||||
}
|
||||
#endif
|
||||
{
|
||||
//tag::popen[]
|
||||
asio::io_context ctx;
|
||||
boost::process::popen proc(ctx, "/usr/bin/addr2line", {argv[0]});
|
||||
asio::write(proc, asio::buffer("main\n"));
|
||||
std::string line;
|
||||
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
|
||||
//end::popen[]
|
||||
}
|
||||
}
|
||||
28
example/sync_io.cpp
Normal file
28
example/sync_io.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
bp::ipstream p;
|
||||
|
||||
bp::child c(
|
||||
"test.exe",
|
||||
bp::std_out > p
|
||||
);
|
||||
|
||||
std::string s;
|
||||
std::getline(p, s);
|
||||
|
||||
c.wait();
|
||||
}
|
||||
18
example/terminate.cpp
Normal file
18
example/terminate.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
bp::child c("test.exe");
|
||||
c.terminate();
|
||||
}
|
||||
34
example/wait.cpp
Normal file
34
example/wait.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
bp::child c("test.exe");
|
||||
c.wait();
|
||||
auto exit_code = c.exit_code();
|
||||
}
|
||||
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
|
||||
bp::child c(
|
||||
"test.exe",
|
||||
io_service,
|
||||
bp::on_exit([&](int exit, const std::error_code& ec_in){})
|
||||
);
|
||||
|
||||
io_service.run();
|
||||
}
|
||||
}
|
||||
30
example/windows.cpp
Normal file
30
example/windows.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/windows.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
int main()
|
||||
{
|
||||
bp::system("test.exe",
|
||||
bp::windows::show);
|
||||
|
||||
|
||||
bp::system("test.exe",
|
||||
bp::on_setup([](auto &e)
|
||||
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
|
||||
bp::on_error([](auto&, const std::error_code & ec)
|
||||
{ std::cerr << ec.message() << std::endl; })
|
||||
);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
for line in sys.stdin:
|
||||
# If line is a 'noisy' warning, don't print it or the following two lines.
|
||||
if ('warning: section' in line and 'is deprecated' in line
|
||||
or 'note: change section name to' in line):
|
||||
next(sys.stdin)
|
||||
next(sys.stdin)
|
||||
else:
|
||||
sys.stdout.write(line)
|
||||
sys.stdout.flush()
|
||||
@@ -12,18 +12,29 @@
|
||||
#ifndef BOOST_PROCESS_HPP
|
||||
#define BOOST_PROCESS_HPP
|
||||
|
||||
#include <boost/process/bind_launcher.hpp>
|
||||
#include <boost/process/default_launcher.hpp>
|
||||
/**
|
||||
* \file boost/process.hpp
|
||||
*
|
||||
* Convenience header which includes all public and platform-independent
|
||||
* boost.process header files.
|
||||
*/
|
||||
|
||||
#include <boost/process/args.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/cmd.hpp>
|
||||
#include <boost/process/env.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/execute.hpp>
|
||||
#include <boost/process/exit_code.hpp>
|
||||
#include <boost/process/ext.hpp>
|
||||
#include <boost/process/pid.hpp>
|
||||
#include <boost/process/popen.hpp>
|
||||
#include <boost/process/process.hpp>
|
||||
#include <boost/process/exe.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/search_path.hpp>
|
||||
#include <boost/process/spawn.hpp>
|
||||
#include <boost/process/system.hpp>
|
||||
#include <boost/process/start_dir.hpp>
|
||||
#include <boost/process/stdio.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
|
||||
/** \file boost/process/args.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::v1::args">args</globalname>\endxmlonly property. It also provides the
|
||||
* alternative name \xmlonly <globalname alt="boost::process::v1::argv">argv</globalname>\endxmlonly .
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the
|
||||
* alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly .
|
||||
*
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::args">args</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::argv">argv</globalname>;
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
@@ -30,10 +30,10 @@ namespace boost {
|
||||
*/
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/basic_cmd.hpp>
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct args_
|
||||
{
|
||||
@@ -138,7 +138,7 @@ struct args_
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
@@ -146,11 +146,11 @@ struct args_
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
@@ -158,12 +158,12 @@ struct args_
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
@@ -171,11 +171,11 @@ struct args_
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
@@ -183,7 +183,7 @@ struct args_
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -268,12 +268,12 @@ spawn("gcc", args+={"--version"});
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::v1::detail::args_ args{};
|
||||
constexpr boost::process::detail::args_ args{};
|
||||
|
||||
///Alias for \xmlonly <globalname alt="boost::process::v1::args">args</globalname> \endxmlonly .
|
||||
constexpr boost::process::v1::detail::args_ argv{};
|
||||
///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly .
|
||||
constexpr boost::process::detail::args_ argv{};
|
||||
|
||||
|
||||
}}}
|
||||
}}
|
||||
|
||||
#endif
|
||||
121
include/boost/process/async.hpp
Normal file
121
include/boost/process/async.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/** \file boost/process/async.hpp
|
||||
|
||||
The header which provides the basic asynchrounous features.
|
||||
It provides the on_exit property, which allows callbacks when the process exits.
|
||||
It also implements the necessary traits for passing an boost::asio::io_service,
|
||||
which is needed for asynchronous communication.
|
||||
|
||||
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
|
||||
into the boost::process namespace for convenience.
|
||||
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_ASYNC_HPP_
|
||||
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
#include <boost/process/detail/on_exit.hpp>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/io_service_ref.hpp>
|
||||
#include <boost/process/detail/posix/async_in.hpp>
|
||||
#include <boost/process/detail/posix/async_out.hpp>
|
||||
#include <boost/process/detail/posix/on_exit.hpp>
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/io_service_ref.hpp>
|
||||
#include <boost/process/detail/windows/async_in.hpp>
|
||||
#include <boost/process/detail/windows/async_out.hpp>
|
||||
#include <boost/process/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct async_tag;
|
||||
|
||||
template<typename T>
|
||||
struct is_io_service : std::false_type {};
|
||||
template<>
|
||||
struct is_io_service<api::io_service_ref> : std::true_type {};
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_service& get_io_service(const Tuple & tup)
|
||||
{
|
||||
auto& ref = *boost::fusion::find_if<is_io_service<boost::mpl::_>>(tup);
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
struct async_builder
|
||||
{
|
||||
boost::asio::io_service * ios;
|
||||
|
||||
void operator()(boost::asio::io_service & ios_) {this->ios = &ios_;};
|
||||
|
||||
typedef api::io_service_ref result_type;
|
||||
api::io_service_ref get_initializer() {return api::io_service_ref (*ios);};
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>
|
||||
{
|
||||
typedef async_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using ::boost::asio::buffer;
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** When an io_service is passed, the on_exit property can be used, to be notified
|
||||
when the child process exits.
|
||||
|
||||
|
||||
The following syntax is valid
|
||||
|
||||
\code{.cpp}
|
||||
on_exit=function;
|
||||
on_exit(function);
|
||||
\endcode
|
||||
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)`.
|
||||
|
||||
\par Example
|
||||
|
||||
\code{.cpp}
|
||||
io_service ios;
|
||||
spawn("ls", on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
\endcode
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */
|
||||
@@ -12,21 +12,21 @@
|
||||
#define BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/async_pipe.hpp>
|
||||
#include <boost/process/detail/posix/async_pipe.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/async_pipe.hpp>
|
||||
#include <boost/process/detail/windows/async_pipe.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
namespace boost { namespace process {
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
|
||||
/** Class implementing an asnychronous I/O-Object for use with boost.asio.
|
||||
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
|
||||
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
|
||||
* boost::asio::posix::stream_descriptor.
|
||||
*
|
||||
@@ -47,34 +47,32 @@ public:
|
||||
*/
|
||||
typedef platform_specific handle_type;
|
||||
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* Initializes source and sink with the same io_context.
|
||||
* 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.
|
||||
@@ -91,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);
|
||||
|
||||
|
||||
@@ -162,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);
|
||||
|
||||
@@ -191,26 +193,26 @@ 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 &;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
using ::boost::process::v1::detail::api::async_pipe;
|
||||
using ::boost::process::detail::api::async_pipe;
|
||||
#endif
|
||||
|
||||
|
||||
}}}
|
||||
}}
|
||||
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
#include <boost/process/v2/bind_launcher.hpp>
|
||||
@@ -17,29 +17,26 @@
|
||||
#ifndef BOOST_PROCESS_CHILD_HPP
|
||||
#define BOOST_PROCESS_CHILD_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/detail/execute_impl.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
///The main namespace of boost.process.
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
namespace process {
|
||||
|
||||
template<typename ...Args>
|
||||
child::child(Args&&...args)
|
||||
: child(::boost::process::v1::detail::execute_impl(std::forward<Args>(args)...)) {}
|
||||
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
|
||||
|
||||
|
||||
///Typedef for the type of an pid_t
|
||||
typedef ::boost::process::v1::detail::api::pid_t pid_t;
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** The main class to hold a child process. It is similar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
|
||||
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
|
||||
* in that it has a join and detach function.
|
||||
*
|
||||
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
|
||||
@@ -92,10 +89,6 @@ class child
|
||||
/** Get the Process Identifier. */
|
||||
pid_t id() const;
|
||||
|
||||
/** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited
|
||||
* for or if it was terminated. */
|
||||
int native_exit_code() const;
|
||||
|
||||
/** Check if the child process is running. */
|
||||
bool running();
|
||||
/** \overload void running() */
|
||||
@@ -106,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 )*/
|
||||
@@ -149,6 +139,6 @@ class child
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
}}
|
||||
#endif
|
||||
|
||||
@@ -1,121 +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/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/cmd.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/cmd.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::v1::cmd">cmd</globalname>\endxmlonly property.
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::cmd">cmd</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() = default;
|
||||
|
||||
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::v1::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::v1::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The cmd property allows to explicitly set commands for the execution.
|
||||
|
||||
The overload form applies when only one string is passed to a launching function.
|
||||
The string will be internally parsed and split at spaces.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t`.
|
||||
|
||||
\code{.cpp}
|
||||
cmd="value";
|
||||
cmd(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::v1::detail::cmd_ cmd;
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
// 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
|
||||
@@ -1 +0,0 @@
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
@@ -1 +0,0 @@
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
152
include/boost/process/detail/async_handler.hpp
Normal file
152
include/boost/process/detail/async_handler.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* async_handler.hpp
|
||||
*
|
||||
* Created on: 12.06.2016
|
||||
* Author: Klemens
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
using ::boost::process::detail::posix::is_async_handler;
|
||||
using ::boost::process::detail::posix::does_require_io_service;
|
||||
#else
|
||||
using ::boost::process::detail::windows::is_async_handler;
|
||||
using ::boost::process::detail::windows::does_require_io_service;
|
||||
#endif
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_io_service;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_io_service<T, Args...>
|
||||
{
|
||||
typedef typename has_io_service<Args...>::type next;
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_service>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_io_service<T>
|
||||
{
|
||||
typedef typename std::is_same<
|
||||
typename std::remove_reference<T>::type,
|
||||
boost::asio::io_service>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
using has_io_service_t = typename has_io_service<Args...>::type;
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_async_handler;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_async_handler<T, Args...>
|
||||
{
|
||||
typedef typename has_async_handler<Args...>::type next;
|
||||
typedef typename is_async_handler<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_async_handler<T>
|
||||
{
|
||||
typedef typename is_async_handler<T>::type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct needs_io_service;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct needs_io_service<T, Args...>
|
||||
{
|
||||
typedef typename needs_io_service<Args...>::type next;
|
||||
typedef typename does_require_io_service<T>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct needs_io_service<T>
|
||||
{
|
||||
typedef typename does_require_io_service<T>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context
|
||||
{
|
||||
typedef std::false_type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct is_yield_context<::boost::asio::basic_yield_context<T>>
|
||||
{
|
||||
typedef std::true_type type;
|
||||
};
|
||||
|
||||
template<typename ...Args>
|
||||
struct has_yield_context;
|
||||
|
||||
template<typename T, typename ...Args>
|
||||
struct has_yield_context<T, Args...>
|
||||
{
|
||||
typedef typename has_yield_context<Args...>::type next;
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type is_ios;
|
||||
typedef typename std::conditional<is_ios::value,
|
||||
std::true_type,
|
||||
next>::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct has_yield_context<T>
|
||||
{
|
||||
typedef typename is_yield_context<
|
||||
typename std::remove_reference<T>::type>::type type;
|
||||
};
|
||||
|
||||
|
||||
template<typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(boost::asio::io_service & f, Args&...args)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
template<typename First, typename ...Args>
|
||||
boost::asio::io_service &get_io_service_var(First & f, Args&...args)
|
||||
{
|
||||
return get_io_service_var(args...);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */
|
||||
@@ -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/v1/detail/config.hpp>
|
||||
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined( BOOST_WINDOWS_API )
|
||||
#include <boost/process/v1/detail/windows/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/windows/cmd.hpp>
|
||||
#elif defined( BOOST_POSIX_API )
|
||||
#include <boost/process/v1/detail/posix/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { 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::v1::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::v1::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::v1::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::v1::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::v1::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::v1::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::process::v1::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_ */
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef BOOST_PROCESS_CHILD_DECL_HPP
|
||||
#define BOOST_PROCESS_CHILD_DECL_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
@@ -25,62 +25,60 @@
|
||||
#include <atomic>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/posix/terminate.hpp>
|
||||
#include <boost/process/v1/detail/posix/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/posix/is_running.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/detail/posix/terminate.hpp>
|
||||
#include <boost/process/detail/posix/wait_for_exit.hpp>
|
||||
#include <boost/process/detail/posix/is_running.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/windows/terminate.hpp>
|
||||
#include <boost/process/v1/detail/windows/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/windows/is_running.hpp>
|
||||
#include <boost/process/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/detail/windows/terminate.hpp>
|
||||
#include <boost/process/detail/windows/wait_for_exit.hpp>
|
||||
#include <boost/process/detail/windows/is_running.hpp>
|
||||
|
||||
#endif
|
||||
namespace boost {
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
namespace process {
|
||||
|
||||
using ::boost::process::v1::detail::api::pid_t;
|
||||
using ::boost::process::detail::api::pid_t;
|
||||
|
||||
class child
|
||||
{
|
||||
::boost::process::v1::detail::api::child_handle _child_handle;
|
||||
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::v1::detail::api::still_active);
|
||||
::boost::process::detail::api::child_handle _child_handle;
|
||||
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active);
|
||||
bool _attached = true;
|
||||
bool _terminated = false;
|
||||
|
||||
bool _exited()
|
||||
{
|
||||
return _terminated || !::boost::process::v1::detail::api::is_running(_exit_status->load());
|
||||
return _terminated || !::boost::process::detail::api::is_running(_exit_status->load());
|
||||
};
|
||||
public:
|
||||
typedef ::boost::process::v1::detail::api::child_handle child_handle;
|
||||
typedef ::boost::process::detail::api::child_handle child_handle;
|
||||
typedef child_handle::process_handle_t native_handle_t;
|
||||
explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
|
||||
|
||||
explicit child(pid_t pid) : _child_handle(pid), _attached(false) {};
|
||||
explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
|
||||
child(const child&) = delete;
|
||||
child(child && lhs) noexcept
|
||||
: _child_handle(std::move(lhs._child_handle)),
|
||||
_exit_status(std::move(lhs._exit_status)),
|
||||
_attached (lhs._attached),
|
||||
_terminated (lhs._terminated)
|
||||
_attached (lhs._attached)
|
||||
{
|
||||
lhs._attached = false;
|
||||
}
|
||||
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
|
||||
child() {}
|
||||
child& operator=(const child&) = delete;
|
||||
child& operator=(child && lhs)
|
||||
{
|
||||
_child_handle= std::move(lhs._child_handle);
|
||||
_exit_status = std::move(lhs._exit_status);
|
||||
_attached = lhs._attached;
|
||||
_terminated = lhs._terminated;
|
||||
lhs._attached = false;
|
||||
return *this;
|
||||
};
|
||||
@@ -98,65 +96,77 @@ public:
|
||||
native_handle_t native_handle() const { return _child_handle.process_handle(); }
|
||||
|
||||
|
||||
int exit_code() const {return ::boost::process::v1::detail::api::eval_exit_status(_exit_status->load());}
|
||||
int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
|
||||
pid_t id() const {return _child_handle.id(); }
|
||||
|
||||
int native_exit_code() const {return _exit_status->load();}
|
||||
|
||||
bool running()
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = running(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "running error");
|
||||
return b;
|
||||
if (valid() && !_exited())
|
||||
{
|
||||
int code;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, code);
|
||||
if (!res && !_exited())
|
||||
_exit_status->store(code);
|
||||
|
||||
return res;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void terminate()
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "terminate error");
|
||||
if (valid() && running())
|
||||
boost::process::detail::api::terminate(_child_handle);
|
||||
|
||||
_terminated = true;
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait error");
|
||||
if (!_exited() && valid())
|
||||
{
|
||||
int exit_code = 0;
|
||||
boost::process::detail::api::wait(_child_handle, exit_code);
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
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;
|
||||
bool b = wait_for(rel_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(timeout_time, ec);
|
||||
boost::process::v1::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
ec.clear();
|
||||
if (valid() && !_exited() && !ec)
|
||||
if (valid() && !_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto res = boost::process::v1::detail::api::is_running(_child_handle, exit_code, ec);
|
||||
if (!ec && !res && !_exited())
|
||||
_exit_status->store(exit_code);
|
||||
int code;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, code, ec);
|
||||
if (!res && !_exited())
|
||||
_exit_status->store(code);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -165,11 +175,10 @@ public:
|
||||
|
||||
void terminate(std::error_code & ec) noexcept
|
||||
{
|
||||
if (valid() && running(ec) && !ec)
|
||||
boost::process::v1::detail::api::terminate(_child_handle, ec);
|
||||
if (valid() && running(ec))
|
||||
boost::process::detail::api::terminate(_child_handle, ec);
|
||||
|
||||
if (!ec)
|
||||
_terminated = true;
|
||||
_terminated = true;
|
||||
}
|
||||
|
||||
void wait(std::error_code & ec) noexcept
|
||||
@@ -177,35 +186,39 @@ public:
|
||||
if (!_exited() && valid())
|
||||
{
|
||||
int exit_code = 0;
|
||||
boost::process::v1::detail::api::wait(_child_handle, exit_code, ec);
|
||||
if (!ec)
|
||||
_exit_status->store(exit_code);
|
||||
boost::process::detail::api::wait(_child_handle, exit_code, ec);
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::v1::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
|
||||
if (!b || ec)
|
||||
auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
|
||||
if (!b)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
@@ -225,7 +238,6 @@ public:
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
95
include/boost/process/detail/config.hpp
Normal file
95
include/boost/process/detail/config.hpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/config.hpp
|
||||
*
|
||||
* Defines various macros.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
#include <boost/process/exception.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <errno.h>
|
||||
#include <features.h>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/detail/winapi/get_last_error.hpp>
|
||||
#else
|
||||
#error "System API not supported by boost.process"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail
|
||||
{
|
||||
|
||||
#if !defined(BOOST_PROCESS_PIPE_SIZE)
|
||||
#define BOOST_PROCESS_PIPE_SIZE 1024
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
namespace posix {namespace extensions {}}
|
||||
namespace api = posix;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(errno, std::system_category());
|
||||
}
|
||||
|
||||
//copied from linux spec.
|
||||
#if defined (__USE_XOPEN_EXTENDED) && !defined (__USE_XOPEN2K8) || defined( __USE_BSD)
|
||||
#define BOOST_POSIX_HAS_VFORK 1
|
||||
#endif
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
namespace windows {namespace extensions {}}
|
||||
namespace api = windows;
|
||||
|
||||
inline std::error_code get_last_error() noexcept
|
||||
{
|
||||
return std::error_code(::boost::detail::winapi::GetLastError(), std::system_category());
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void throw_last_error(const std::string & msg)
|
||||
{
|
||||
throw process_error(get_last_error(), msg);
|
||||
}
|
||||
|
||||
inline void throw_last_error()
|
||||
{
|
||||
throw process_error(get_last_error());
|
||||
}
|
||||
|
||||
|
||||
template<typename Char> constexpr 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 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 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 static Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
|
||||
}}}
|
||||
#endif
|
||||
@@ -17,17 +17,17 @@
|
||||
#ifndef BOOST_PROCESS_EXECUTE_HPP
|
||||
#define BOOST_PROCESS_EXECUTE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/executor.hpp>
|
||||
#include <boost/process/detail/posix/executor.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/executor.hpp>
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/v1/detail/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/handler.hpp>
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
|
||||
#include <boost/fusion/view.hpp>
|
||||
#include <boost/fusion/container.hpp>
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
namespace boost { namespace process {
|
||||
|
||||
class child;
|
||||
|
||||
@@ -228,7 +228,7 @@ inline child basic_execute_impl(Args && ... args)
|
||||
boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
|
||||
|
||||
auto inits = boost::fusion::filter_if<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
boost::process::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
@@ -237,7 +237,7 @@ inline child basic_execute_impl(Args && ... args)
|
||||
|
||||
auto others = boost::fusion::filter_if<
|
||||
boost::mpl::not_<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
boost::process::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
@@ -250,20 +250,20 @@ inline child basic_execute_impl(Args && ... args)
|
||||
//typedef typename boost::fusion::result_of::as_vector<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::v1::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::v1::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::v1::detail::get_initializers(builders);
|
||||
auto other_inits = ::boost::process::detail::get_initializers(builders);
|
||||
|
||||
|
||||
boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
|
||||
|
||||
auto exec = boost::process::v1::detail::api::make_executor<Char>(complete_inits);
|
||||
auto exec = boost::process::detail::api::make_executor<Char>(complete_inits);
|
||||
return exec();
|
||||
}
|
||||
|
||||
@@ -273,11 +273,12 @@ inline child execute_impl(Args&& ... args)
|
||||
typedef required_char_type_t<Args...> req_char_type;
|
||||
|
||||
return basic_execute_impl<req_char_type>(
|
||||
boost::process::v1::detail::char_converter_t<req_char_type, Args>::conv(
|
||||
boost::process::detail::char_converter_t<req_char_type, Args>::conv(
|
||||
std::forward<Args>(args))...
|
||||
);
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,73 +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/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { 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_ */
|
||||
@@ -11,15 +11,13 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
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>
|
||||
@@ -45,6 +43,6 @@ struct handler_base
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -6,18 +6,18 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/on_exit.hpp>
|
||||
#include <boost/process/detail/posix/on_exit.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/on_exit.hpp>
|
||||
#include <boost/process/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f)
|
||||
{
|
||||
@@ -46,9 +46,8 @@ struct on_exit_
|
||||
|
||||
}
|
||||
|
||||
constexpr static ::boost::process::v1::detail::on_exit_ on_exit{};
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
@@ -7,7 +7,6 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
@@ -21,24 +20,39 @@ template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
class io_service;
|
||||
|
||||
|
||||
class signal_set_service;
|
||||
template <typename SignalSetService>
|
||||
|
||||
template <typename Executor>
|
||||
class basic_signal_set;
|
||||
typedef basic_signal_set<any_io_executor> signal_set;
|
||||
typedef basic_signal_set<signal_set_service> signal_set;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace posix {
|
||||
|
||||
template <typename Executor>
|
||||
class stream_descriptor_service;
|
||||
|
||||
template <typename StreamDesscriptorService>
|
||||
class basic_stream_descriptor;
|
||||
typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
|
||||
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
|
||||
|
||||
|
||||
|
||||
class object_handle_service;
|
||||
|
||||
template <typename ObjectHandleService>
|
||||
class basic_object_handle;
|
||||
|
||||
typedef basic_object_handle<object_handle_service> object_handle;
|
||||
|
||||
} //posix
|
||||
} //asio
|
||||
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace process { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe;
|
||||
|
||||
@@ -54,9 +68,8 @@ struct async_out_future;
|
||||
} // posix
|
||||
} // detail
|
||||
|
||||
using ::boost::process::v1::detail::posix::async_pipe;
|
||||
using ::boost::process::detail::posix::async_pipe;
|
||||
|
||||
} // v1
|
||||
} // process
|
||||
} // boost
|
||||
|
||||
@@ -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/v1/detail/posix/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { 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_ */
|
||||
94
include/boost/process/detail/posix/async_in.hpp
Normal file
94
include/boost/process/detail/posix/async_in.hpp
Normal file
@@ -0,0 +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_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
|
||||
@@ -1,190 +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/v1/detail/posix/handler.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <array>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { 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::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
const auto pp1 = p1 != -1 ? p1 : p2;
|
||||
const auto pp2 = p2 != -1 ? p2 : p1;
|
||||
|
||||
if (pipe)
|
||||
return {pipe->native_source(), pipe->native_sink(), pp1, pp2};
|
||||
else //if pipe is not constructed, limit_ds is invoked before -> this also means on_exec_setup gets invoked before.
|
||||
return {pp1, pp2, pp1, pp2};
|
||||
}
|
||||
|
||||
|
||||
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){});
|
||||
|
||||
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::v1::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::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::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::v1::async_pipe> pipe;
|
||||
|
||||
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;
|
||||
|
||||
boost::asio::async_read(*pipe_, *buffer_,
|
||||
[pipe_, buffer_, promise_](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
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;
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
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::v1::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::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::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_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
|
||||
@@ -7,63 +7,55 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe
|
||||
{
|
||||
::boost::asio::posix::stream_descriptor _source;
|
||||
::boost::asio::posix::stream_descriptor _sink ;
|
||||
public:
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
typedef int native_handle;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{
|
||||
return _source.get_executor();
|
||||
}
|
||||
inline async_pipe(boost::asio::io_service & ios) : async_pipe(ios, ios) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & 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)
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
boost::process::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_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))
|
||||
{
|
||||
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
|
||||
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
|
||||
lhs._source.assign (-1);
|
||||
lhs._sink .assign (-1);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
@@ -76,8 +68,10 @@ public:
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
close(ec);
|
||||
if (_sink .native() != -1)
|
||||
::close(_sink.native());
|
||||
if (_source.native() != -1)
|
||||
::close(_source.native());
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
@@ -114,9 +108,9 @@ public:
|
||||
void async_close()
|
||||
{
|
||||
if (_sink.is_open())
|
||||
boost::asio::post(_sink.get_executor(), [this]{_sink.close();});
|
||||
_sink.get_io_service(). post([this]{_sink.close();});
|
||||
if (_source.is_open())
|
||||
boost::asio::post(_source.get_executor(), [this]{_source.close();});
|
||||
_source.get_io_service().post([this]{_source.close();});
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
@@ -130,21 +124,10 @@ public:
|
||||
return _sink.write_some(buffers);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _source.read_some(buffers, ec);
|
||||
}
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers, boost::system::error_code & ec) noexcept
|
||||
{
|
||||
return _sink.write_some(buffers, ec);
|
||||
}
|
||||
native_handle native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native();}
|
||||
native_handle native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native();}
|
||||
|
||||
|
||||
native_handle_type native_source() const {return const_cast<boost::asio::posix::stream_descriptor&>(_source).native_handle();}
|
||||
native_handle_type native_sink () const {return const_cast<boost::asio::posix::stream_descriptor&>(_sink ).native_handle();}
|
||||
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||
@@ -153,7 +136,7 @@ public:
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler)
|
||||
{
|
||||
return _source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
_source.async_read_some(buffers, std::forward<ReadHandler>(handler));
|
||||
}
|
||||
|
||||
template<typename ConstBufferSequence,
|
||||
@@ -164,79 +147,81 @@ public:
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler&& handler)
|
||||
{
|
||||
return _sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
_sink.async_write_some(buffers, std::forward<WriteHandler>(handler));
|
||||
}
|
||||
|
||||
|
||||
const handle_type & sink () const & {return _sink;}
|
||||
const handle_type & source() const & {return _source;}
|
||||
|
||||
handle_type && sink() && { return std::move(_sink); }
|
||||
handle_type && source()&& { return std::move(_source); }
|
||||
handle_type && source()&& { 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 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
boost::process::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
boost::process::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
boost::process::detail::throw_last_error();
|
||||
|
||||
_source.assign(read_fd);
|
||||
_sink .assign(write_fd);
|
||||
}
|
||||
|
||||
async_pipe::async_pipe(const async_pipe & p) :
|
||||
_source(const_cast<async_pipe&>(p)._source.get_executor()),
|
||||
_sink( const_cast<async_pipe&>(p)._sink.get_executor())
|
||||
_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)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
if (_source.native()== -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -244,8 +229,8 @@ async_pipe::async_pipe(const async_pipe & p) :
|
||||
else
|
||||
{
|
||||
_sink.assign(::dup(sink_in));
|
||||
if (_sink.native_handle() == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
if (_sink.native() == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,15 +240,15 @@ 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 &>(p._source).native_handle();
|
||||
auto sink_in = const_cast<::boost::asio::posix::stream_descriptor &>(p._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
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -272,7 +257,7 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
_source.assign(source);
|
||||
_sink. assign(sink);
|
||||
@@ -282,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;
|
||||
}
|
||||
|
||||
@@ -294,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)
|
||||
@@ -304,7 +297,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -313,10 +306,10 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
return {source, sink};
|
||||
}
|
||||
|
||||
|
||||
@@ -360,6 +353,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe &
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
|
||||
@@ -7,11 +7,10 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <string>
|
||||
@@ -21,13 +20,12 @@ namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
|
||||
inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
|
||||
{
|
||||
std::string st = exe;
|
||||
@@ -41,10 +39,10 @@ inline std::string build_cmd_shell(const std::string & exe, std::vector<std::str
|
||||
//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 += '"'; //that is the post one.
|
||||
arg += '"'; //thats the post one.
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
@@ -103,7 +101,7 @@ template<typename Char>
|
||||
struct exe_cmd_init;
|
||||
|
||||
template<>
|
||||
struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
|
||||
struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
exe_cmd_init(const exe_cmd_init & ) = delete;
|
||||
exe_cmd_init(exe_cmd_init && ) = default;
|
||||
@@ -112,19 +110,17 @@ struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
|
||||
template <class Executor>
|
||||
void on_setup(Executor& exec)
|
||||
{
|
||||
if (exe.empty()) //cmd style
|
||||
{
|
||||
if (args.empty())
|
||||
exec.exe = "";
|
||||
else
|
||||
exec.exe = args.front().c_str();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
if (exe.empty())
|
||||
exec.exe = args.front().c_str();
|
||||
else
|
||||
exec.exe = &exe.front();
|
||||
|
||||
cmd_impl = make_cmd();
|
||||
exec.cmd_line = cmd_impl.data();
|
||||
|
||||
if (!args.empty())
|
||||
{
|
||||
cmd_impl = make_cmd();
|
||||
exec.cmd_line = cmd_impl.data();
|
||||
}
|
||||
}
|
||||
static exe_cmd_init exe_args(std::string && exe, std::vector<std::string> && args) {return exe_cmd_init(std::move(exe), std::move(args));}
|
||||
static exe_cmd_init cmd (std::string && cmd)
|
||||
@@ -144,7 +140,7 @@ struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
|
||||
}
|
||||
static exe_cmd_init cmd_shell(std::string&& cmd)
|
||||
{
|
||||
std::vector<std::string> args = {"-c", cmd};
|
||||
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
|
||||
std::string sh = shell().string();
|
||||
|
||||
return exe_cmd_init(
|
||||
@@ -160,16 +156,12 @@ private:
|
||||
|
||||
std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
{
|
||||
// any string must be writable.
|
||||
static char empty_string[1] = "";
|
||||
std::vector<char*> vec;
|
||||
if (!exe.empty())
|
||||
vec.push_back(exe.empty() ? empty_string : &exe.front());
|
||||
vec.push_back(&exe.front());
|
||||
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(v.empty() ? empty_string : &v.front());
|
||||
}
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
|
||||
vec.push_back(nullptr);
|
||||
|
||||
@@ -177,6 +169,6 @@ std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
}
|
||||
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,15 +11,15 @@
|
||||
#define BOOST_PROCESS_POSIX_PIPE_HPP
|
||||
|
||||
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/process/v1/detail/posix/compare_handles.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/detail/posix/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <array>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
@@ -29,19 +29,19 @@ 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()
|
||||
{
|
||||
int fds[2];
|
||||
if (::pipe(fds) == -1)
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
boost::process::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_source = fds[0];
|
||||
_sink = fds[1];
|
||||
@@ -71,38 +71,28 @@ public:
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
}
|
||||
native_handle_type native_source() const {return _source;}
|
||||
native_handle_type native_sink () const {return _sink;}
|
||||
native_handle native_source() const {return _source;}
|
||||
native_handle native_sink () const {return _sink;}
|
||||
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
ssize_t write_len;
|
||||
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return static_cast<int_type>(write_len);
|
||||
auto write_len = ::write(_sink, data, count * sizeof(char_type));
|
||||
if (write_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
return write_len;
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
ssize_t read_len;
|
||||
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return static_cast<int_type>(read_len);
|
||||
auto read_len = ::read(_source, data, count * sizeof(char_type));
|
||||
if (read_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
bool is_open()
|
||||
{
|
||||
return (_source != -1) ||
|
||||
(_sink != -1);
|
||||
@@ -110,10 +100,8 @@ public:
|
||||
|
||||
void close()
|
||||
{
|
||||
if (_source != -1)
|
||||
::close(_source);
|
||||
if (_sink != -1)
|
||||
::close(_sink);
|
||||
::close(_source);
|
||||
::close(_sink);
|
||||
_source = -1;
|
||||
_sink = -1;
|
||||
}
|
||||
@@ -126,13 +114,13 @@ basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -144,13 +132,13 @@ basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
return *this;
|
||||
@@ -163,18 +151,18 @@ basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
|
||||
auto fifo = mkfifo(name.c_str(), 0666 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
boost::process::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
boost::process::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
boost::process::detail::throw_last_error();
|
||||
|
||||
_sink = write_fd;
|
||||
_source = read_fd;
|
||||
@@ -195,6 +183,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Ch
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <utility>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
typedef ::pid_t pid_t;
|
||||
|
||||
@@ -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; }
|
||||
@@ -55,6 +55,6 @@ struct child_handle
|
||||
}
|
||||
};
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,24 +11,20 @@
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct close_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
struct close_in : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return STDIN_FILENO;}
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -10,19 +10,16 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct close_out : handler_base_ext
|
||||
{
|
||||
template <class Executor>
|
||||
inline void on_exec_setup(Executor &e) const;
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {{p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1}};}
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -30,7 +27,7 @@ template<typename Executor>
|
||||
void close_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +36,7 @@ template<typename Executor>
|
||||
void close_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -47,12 +44,12 @@ template<typename Executor>
|
||||
void close_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -16,14 +16,13 @@ namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline std::vector<std::basic_string<Char>> build_cmd(const std::basic_string<Char> & value)
|
||||
{
|
||||
@@ -62,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
|
||||
{
|
||||
@@ -101,6 +98,6 @@ std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Cha
|
||||
return vec;
|
||||
}
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,12 +7,12 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline bool compare_handles(int lhs, int rhs)
|
||||
@@ -25,8 +25,8 @@ inline bool compare_handles(int lhs, int rhs)
|
||||
return true;
|
||||
|
||||
struct stat stat1, stat2;
|
||||
if(fstat(lhs, &stat1) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(rhs, &stat2) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(lhs, &stat1) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(rhs, &stat2) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
|
||||
|
||||
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ inline bool compare_handles(int lhs, int rhs)
|
||||
|
||||
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
struct env_init;
|
||||
@@ -20,10 +20,10 @@ struct env_init;
|
||||
template<>
|
||||
struct env_init<char> : handler_base_ext
|
||||
{
|
||||
boost::process::v1::environment env;
|
||||
boost::process::environment env;
|
||||
|
||||
env_init(boost::process::v1::environment && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::v1::environment & env) : env(env) {};
|
||||
env_init(boost::process::environment && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::environment & env) : env(env) {};
|
||||
|
||||
|
||||
template <class Executor>
|
||||
@@ -34,7 +34,7 @@ struct env_init<char> : handler_base_ext
|
||||
|
||||
};
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
@@ -1,327 +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/v1/detail/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { 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::v1::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);
|
||||
_env_impl = _impl.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), 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::v1::detail::convert(id);
|
||||
std::string g = ::getenv(id_c.c_str());
|
||||
return ::boost::process::v1::detail::convert(g.c_str());
|
||||
}
|
||||
void set(const string_type & id, const string_type & value)
|
||||
{
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
std::string value_c = ::boost::process::v1::detail::convert(value.c_str());
|
||||
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
|
||||
if (res != 0)
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
void reset(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
auto res = ::unsetenv(id_c.c_str());
|
||||
if (res != 0)
|
||||
::boost::process::v1::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 _env_impl;}
|
||||
};
|
||||
|
||||
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::v1::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
void reset(const pointer_type id)
|
||||
{
|
||||
auto res = ::unsetenv(id);
|
||||
if (res != 0)
|
||||
boost::process::v1::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::v1::codecvt_type & cv = ::boost::process::v1::codecvt())
|
||||
: _data(rhs._data.size())
|
||||
{
|
||||
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
|
||||
[&](const std::basic_string<CharR> & st)
|
||||
{
|
||||
return ::boost::process::v1::detail::convert(st, cv);
|
||||
}
|
||||
|
||||
);
|
||||
reload();
|
||||
}
|
||||
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
_data = ::boost::process::v1::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) -> bool
|
||||
{
|
||||
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) -> bool
|
||||
{
|
||||
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) -> bool
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (val.empty())
|
||||
val.push_back(0);
|
||||
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_ */
|
||||
@@ -7,14 +7,11 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
@@ -33,7 +30,7 @@ inline void apply_exe(const StringType & exe, Executor & e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
@@ -8,13 +8,13 @@
|
||||
// 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/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/use_vfork.hpp>
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/detail/posix/use_vfork.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
@@ -22,13 +22,8 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_t
|
||||
@@ -52,7 +47,7 @@ struct on_error_t
|
||||
template<typename T>
|
||||
void operator()(T & t) const
|
||||
{
|
||||
t.on_error(exec, error);
|
||||
t.on_error(exec, error);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,34 +105,20 @@ 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)
|
||||
template<typename Executor> on_error_t <Executor> call_on_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_error_t<Executor> (exec, ec);
|
||||
}
|
||||
template<typename Executor> on_success_t<Executor> call_on_success(Executor & exec) {return exec;}
|
||||
|
||||
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
|
||||
template<typename Executor> on_fork_error_t <Executor> call_on_fork_error (Executor & exec, const std::error_code & ec)
|
||||
{
|
||||
return on_fork_error_t<Executor> (exec, ec);
|
||||
}
|
||||
|
||||
|
||||
template<typename Executor> on_exec_setup_t <Executor> call_on_exec_setup (Executor & exec) {return exec;}
|
||||
template<typename Executor> on_exec_error_t <Executor> call_on_exec_error (Executor & exec, const std::error_code & ec)
|
||||
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);
|
||||
}
|
||||
@@ -147,19 +128,19 @@ 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;
|
||||
|
||||
|
||||
void write_error(const std::error_code & ec, const char * msg)
|
||||
{
|
||||
//I am the child
|
||||
const auto len = static_cast<int>(std::strlen(msg));
|
||||
int data[2] = {ec.value(), len + 1};
|
||||
int len = ec.value();
|
||||
::write(_pipe_sink, &len, sizeof(int));
|
||||
|
||||
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
|
||||
boost::ignore_unused(::write(_pipe_sink, msg, len));
|
||||
len = std::strlen(msg) + 1;
|
||||
::write(_pipe_sink, &len, sizeof(int));
|
||||
::write(_pipe_sink, msg, len);
|
||||
}
|
||||
|
||||
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
|
||||
@@ -200,13 +181,13 @@ 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::v1::detail::has_error_handler<Sequence>::type has_error_handler;
|
||||
typedef typename ::boost::process::v1::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
typedef typename ::boost::process::v1::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
|
||||
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_ );
|
||||
@@ -260,44 +241,13 @@ class executor
|
||||
auto err = errno;
|
||||
if ((err == EBADF) || (err == EPERM))//that should occur on success, therefore return.
|
||||
return;
|
||||
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
|
||||
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
|
||||
else if ((err != EAGAIN ) && (err != EINTR))
|
||||
set_error(std::error_code(err, std::system_category()), "Error read pipe");
|
||||
}
|
||||
set_error(ec, std::move(msg));
|
||||
}
|
||||
|
||||
std::string prepare_cmd_style_fn; //buffer
|
||||
|
||||
inline void prepare_cmd_style() //this does what execvpe does - but we execute it in the father process, to avoid allocations.
|
||||
{
|
||||
//use my own implementation
|
||||
prepare_cmd_style_fn = exe;
|
||||
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
|
||||
{
|
||||
const auto * e = environ;
|
||||
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if ((e != nullptr) && (*e != nullptr))
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
//the beginning of the string contains "PATH="
|
||||
boost::split(path, (*e) + 5, boost::is_any_of(":"));
|
||||
|
||||
for (const std::string & pp : path)
|
||||
{
|
||||
auto p = pp + "/" + exe;
|
||||
if (!::access(p.c_str(), X_OK))
|
||||
{
|
||||
prepare_cmd_style_fn = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exe = prepare_cmd_style_fn.c_str();
|
||||
}
|
||||
|
||||
std::error_code _ec;
|
||||
std::string _msg;
|
||||
@@ -315,8 +265,7 @@ public:
|
||||
Sequence & seq;
|
||||
const char * exe = nullptr;
|
||||
char *const* cmd_line = nullptr;
|
||||
bool cmd_style = false;
|
||||
char **env = environ;
|
||||
char **env = ::environ;
|
||||
pid_t pid = -1;
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
@@ -328,13 +277,6 @@ public:
|
||||
}
|
||||
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
|
||||
|
||||
std::vector<int> get_used_handles() const
|
||||
{
|
||||
if (_pipe_sink == -1)
|
||||
return {};
|
||||
else
|
||||
return {_pipe_sink};
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
@@ -343,13 +285,11 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
if (_ec)
|
||||
return child();
|
||||
if (cmd_style)
|
||||
prepare_cmd_style();
|
||||
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
@@ -357,7 +297,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -372,92 +312,65 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
template<typename Sequence>
|
||||
child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
{
|
||||
int p[2];
|
||||
if (::pipe(p) == -1)
|
||||
{
|
||||
struct pipe_guard
|
||||
{
|
||||
int p[2];
|
||||
pipe_guard() : p{-1,-1} {}
|
||||
|
||||
~pipe_guard()
|
||||
{
|
||||
if (p[0] != -1)
|
||||
::close(p[0]);
|
||||
if (p[1] != -1)
|
||||
::close(p[1]);
|
||||
}
|
||||
} p{};
|
||||
|
||||
if (::pipe(p.p) == -1)
|
||||
{
|
||||
set_error(::boost::process::v1::detail::get_last_error(), "pipe(2) failed");
|
||||
return child();
|
||||
}
|
||||
if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
auto err = ::boost::process::v1::detail::get_last_error();
|
||||
set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
|
||||
return child();
|
||||
}
|
||||
|
||||
_pipe_sink = p.p[1];
|
||||
|
||||
_ec.clear();
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
|
||||
if (cmd_style)
|
||||
prepare_cmd_style();
|
||||
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
::close(p.p[0]);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_write_error(_pipe_sink);
|
||||
::close(p.p[1]);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
|
||||
::close(p.p[1]);
|
||||
p.p[1] = -1;
|
||||
_pipe_sink = -1;
|
||||
_read_error(p.p[0]);
|
||||
|
||||
set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
|
||||
return child();
|
||||
}
|
||||
if (::fcntl(p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
set_error(::boost::process::detail::get_last_error(), "fcntl(2) failed");
|
||||
return child();
|
||||
}
|
||||
_ec.clear();
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
//if an error occurred we need to reap the child process
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
_pipe_sink = p[1];
|
||||
::close(p[0]);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_write_error(p[1]);
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
::close(p[1]);
|
||||
_read_error(p[0]);
|
||||
::close(p[0]);
|
||||
|
||||
if (_ec)
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
else
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
@@ -477,10 +390,11 @@ 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)
|
||||
{
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
@@ -488,10 +402,11 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
@@ -510,13 +425,10 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
return child();
|
||||
}
|
||||
_ec.clear();
|
||||
if (cmd_style)
|
||||
this->prepare_cmd_style();
|
||||
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
@@ -528,26 +440,22 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
return child();
|
||||
}
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
check_error(has_error_handler());
|
||||
|
||||
child c(child_handle(pid), exit_status);
|
||||
|
||||
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
else
|
||||
boost::fusion::for_each(seq, call_on_success(*this));
|
||||
|
||||
@@ -568,6 +476,6 @@ inline executor<Tup> make_executor(Tup & tup)
|
||||
return executor<Tup>(tup);
|
||||
}
|
||||
|
||||
}}}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user