mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
300 Commits
boost-1.71
...
origin/xpr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4ba43e970 | ||
|
|
19212708e5 | ||
|
|
42ba48f744 | ||
|
|
1e60fcd830 | ||
|
|
d6bcb0014a | ||
|
|
e5f0f245bd | ||
|
|
a4a3770501 | ||
|
|
1e5892b8fb | ||
|
|
85b29d6442 | ||
|
|
b9ee759365 | ||
|
|
f3b163a933 | ||
|
|
be2ae2c3cf | ||
|
|
b2f5ebc760 | ||
|
|
e34557faa0 | ||
|
|
a9f083f45c | ||
|
|
b5ab94c932 | ||
|
|
9ceda79fa2 | ||
|
|
68cbeae491 | ||
|
|
ae778f36a8 | ||
|
|
0671e4a133 | ||
|
|
cbf944c57b | ||
|
|
5f2b8c53f4 | ||
|
|
dac3614a38 | ||
|
|
2fc71ca0a3 | ||
|
|
404682d75d | ||
|
|
9fbbdc3421 | ||
|
|
3df0009a2f | ||
|
|
ecb384b253 | ||
|
|
05bce942c1 | ||
|
|
dcf5d8ce41 | ||
|
|
4209f8ee6e | ||
|
|
d9513269cc | ||
|
|
293f28dab6 | ||
|
|
fe1b629b5d | ||
|
|
278fa57214 | ||
|
|
1addfba12e | ||
|
|
4cc469b2a4 | ||
|
|
6e4d1e29d2 | ||
|
|
dada865fd0 | ||
|
|
380dd1b00f | ||
|
|
7832cb6af3 | ||
|
|
68f4c50be9 | ||
|
|
cd226a7616 | ||
|
|
4243ce72f8 | ||
|
|
9065833e61 | ||
|
|
7cb7af6c8b | ||
|
|
90cbe7cec0 | ||
|
|
df33c1ad7b | ||
|
|
bbabea30dd | ||
|
|
c1b6eb4eb8 | ||
|
|
4ef1792b0a | ||
|
|
1a6956134a | ||
|
|
eb6bce0910 | ||
|
|
9a1c6991c9 | ||
|
|
352b6cf89f | ||
|
|
317b1b7c62 | ||
|
|
a7b65bfc44 | ||
|
|
ee945a6b95 | ||
|
|
992de7b6ea | ||
|
|
6e597b5c8a | ||
|
|
1a1d677d76 | ||
|
|
c1fb7758b2 | ||
|
|
e24af699cf | ||
|
|
e585864cf4 | ||
|
|
69a0615530 | ||
|
|
26f4584e1e | ||
|
|
43e845a691 | ||
|
|
4d59330067 | ||
|
|
f59c1c180e | ||
|
|
618c931188 | ||
|
|
727881649c | ||
|
|
dd4bf8d857 | ||
|
|
9d006cdd94 | ||
|
|
442a6ed8d8 | ||
|
|
686945f46f | ||
|
|
8979836f32 | ||
|
|
4dfc1bd4fd | ||
|
|
f90edf44e1 | ||
|
|
f56e42fd2e | ||
|
|
b9420be981 | ||
|
|
548ea7d999 | ||
|
|
f453d93e83 | ||
|
|
693a33010d | ||
|
|
faad3fa4df | ||
|
|
4e2e580b4c | ||
|
|
d60ea9c4d3 | ||
|
|
a911da2c1f | ||
|
|
f0c98aa97f | ||
|
|
062ac9beb2 | ||
|
|
fb48747fc8 | ||
|
|
f2a0367605 | ||
|
|
3163496b70 | ||
|
|
4e64224ef1 | ||
|
|
25669a78de | ||
|
|
910192e2ad | ||
|
|
15984e3288 | ||
|
|
6aa704c208 | ||
|
|
62d40caddd | ||
|
|
d63d502b40 | ||
|
|
3a401dd306 | ||
|
|
3893a96c6e | ||
|
|
76c393fb8e | ||
|
|
4fce3c8184 | ||
|
|
54b698dcbd | ||
|
|
1f45677518 | ||
|
|
1493e365ed | ||
|
|
5e5e0b8641 | ||
|
|
932ac3038e | ||
|
|
00bc1ccf47 | ||
|
|
257da990d5 | ||
|
|
c6a812e401 | ||
|
|
f93290d3d4 | ||
|
|
a46ab25046 | ||
|
|
1b61ba6ea7 | ||
|
|
27f79e1774 | ||
|
|
0fbfa1cdc1 | ||
|
|
47c4496d05 | ||
|
|
8a61f8daa3 | ||
|
|
c473251709 | ||
|
|
7bdf11f550 | ||
|
|
dbcc946dac | ||
|
|
e0e801cbb4 | ||
|
|
4943c74e8e | ||
|
|
0733217423 | ||
|
|
397e685053 | ||
|
|
610b337fa3 | ||
|
|
bbb7dced5c | ||
|
|
ab82e78c3d | ||
|
|
a295cd8635 | ||
|
|
b8bcfa2e11 | ||
|
|
ed659bf129 | ||
|
|
4cadf1d333 | ||
|
|
220bec28bf | ||
|
|
ee3c2cfeeb | ||
|
|
221550a848 | ||
|
|
b7821ccf09 | ||
|
|
1f464b3eb5 | ||
|
|
5abb4f4a23 | ||
|
|
722bd31cdb | ||
|
|
e358dc52a2 | ||
|
|
d54788a385 | ||
|
|
4a5d711c86 | ||
|
|
d11e327ab0 | ||
|
|
edaf70a7a7 | ||
|
|
dc8ba65c77 | ||
|
|
ea26c7b2bd | ||
|
|
4d1c438d91 | ||
|
|
d231979a6c | ||
|
|
a3e8600e40 | ||
|
|
c1d0f1be76 | ||
|
|
10c93d88a1 | ||
|
|
5f80e72e9c | ||
|
|
d26ef52519 | ||
|
|
f4d2c260d4 | ||
|
|
e32651a260 | ||
|
|
71aa7d9c00 | ||
|
|
ed3b066da1 | ||
|
|
83380dad79 | ||
|
|
5ad5e82577 | ||
|
|
3acc1a3fa8 | ||
|
|
9bb088ed5d | ||
|
|
cd4ef692e1 | ||
|
|
268795f3c0 | ||
|
|
f8f9c2323c | ||
|
|
0c3ded6636 | ||
|
|
20b328dbf1 | ||
|
|
a60203dac3 | ||
|
|
6d08cb369e | ||
|
|
8dc5ee22f5 | ||
|
|
f7053f31ec | ||
|
|
a13a60d428 | ||
|
|
fa2a522ef2 | ||
|
|
2b39b56efb | ||
|
|
5a283e5200 | ||
|
|
3d5f449052 | ||
|
|
aefb990a7a | ||
|
|
3d092498b2 | ||
|
|
7d7476343a | ||
|
|
e08374ed95 | ||
|
|
155ebdcf1f | ||
|
|
a9925a5d6d | ||
|
|
741d3f4a07 | ||
|
|
f195243a81 | ||
|
|
8c5ab02192 | ||
|
|
b526ac7ce5 | ||
|
|
8222a57744 | ||
|
|
aa3ae06ab7 | ||
|
|
1b4d67170f | ||
|
|
e3594034eb | ||
|
|
ee983eba64 | ||
|
|
0eb4685558 | ||
|
|
7cf1a3b8e6 | ||
|
|
c0a1a82361 | ||
|
|
532951902f | ||
|
|
642c2d369f | ||
|
|
d7a721ee0d | ||
|
|
baa8d3fe7c | ||
|
|
42bdfb5545 | ||
|
|
0f053c323e | ||
|
|
036c9fc4d1 | ||
|
|
b2a96a3e13 | ||
|
|
1dbb3626a9 | ||
|
|
d79e1f2443 | ||
|
|
605dcd19d8 | ||
|
|
6b6a6fa61c | ||
|
|
295e2bdd9c | ||
|
|
dd1513846b | ||
|
|
7a94abfaf2 | ||
|
|
b55a09479c | ||
|
|
5afb20760c | ||
|
|
eec87e1dd9 | ||
|
|
f250a33fb4 | ||
|
|
570cf83a96 | ||
|
|
d52d244f83 | ||
|
|
04ab646f12 | ||
|
|
31c65b5442 | ||
|
|
ebbb6d8b36 | ||
|
|
b9c0140a26 | ||
|
|
27f587a4be | ||
|
|
7f6061c956 | ||
|
|
2f32c95341 | ||
|
|
a8029fc191 | ||
|
|
9f4bd9bce3 | ||
|
|
71f844c24f | ||
|
|
b0b6d67e6f | ||
|
|
3a2576a4d8 | ||
|
|
34eaa262dd | ||
|
|
ce3b3d8f99 | ||
|
|
429f2ba95c | ||
|
|
0c2e7387c8 | ||
|
|
2a2ea4b92d | ||
|
|
873ab2558d | ||
|
|
03571d4eaf | ||
|
|
46ab3ba9b8 | ||
|
|
3aba1f6eb1 | ||
|
|
44771769fa | ||
|
|
8704416941 | ||
|
|
f48392399f | ||
|
|
80f81117aa | ||
|
|
9cff55215d | ||
|
|
2e4b3c2406 | ||
|
|
b510b6a9d9 | ||
|
|
046b96186f | ||
|
|
1df2e67bc4 | ||
|
|
6cf69e2797 | ||
|
|
d3e4cbf3b3 | ||
|
|
e67e49c891 | ||
|
|
29a43b17e4 | ||
|
|
6d10c3a807 | ||
|
|
668579ed6f | ||
|
|
8af828cd43 | ||
|
|
590cc10b42 | ||
|
|
3bc11ce3ac | ||
|
|
603441ecc3 | ||
|
|
612a953369 | ||
|
|
1554773d39 | ||
|
|
dd003bf2b0 | ||
|
|
0341e08297 | ||
|
|
5853345715 | ||
|
|
41f8b1cf00 | ||
|
|
56ae00c7a4 | ||
|
|
f58882c956 | ||
|
|
3f14ebc755 | ||
|
|
1502de1001 | ||
|
|
8541cae396 | ||
|
|
38fa1fd040 | ||
|
|
ba15f760ab | ||
|
|
5e3e8f977e | ||
|
|
6182876d4f | ||
|
|
5bfd2ee08c | ||
|
|
c91b227c47 | ||
|
|
6a4d2ff721 | ||
|
|
6bf37ea8e8 | ||
|
|
ad38cdfada | ||
|
|
167ee79fa9 | ||
|
|
6b83d0b9dd | ||
|
|
16d16d40be | ||
|
|
f5f0866745 | ||
|
|
408cff1997 | ||
|
|
09faec4732 | ||
|
|
5ab43529b7 | ||
|
|
97f5b3c049 | ||
|
|
6dd3e0bdb4 | ||
|
|
eba5cb7be2 | ||
|
|
f4c51bcd5a | ||
|
|
410c0d592e | ||
|
|
40df7899b2 | ||
|
|
51083a8fa8 | ||
|
|
fe3cb0efc7 | ||
|
|
e0dd3b9658 | ||
|
|
d7d84f3952 | ||
|
|
6ccce9104a | ||
|
|
984c0c5b71 | ||
|
|
43523fcf8b | ||
|
|
cf7ad36438 | ||
|
|
ca994c1972 | ||
|
|
192191ecfb | ||
|
|
3aeb6601cd | ||
|
|
8a7c37617e | ||
|
|
1b6ccb6d39 |
38
.drone.star
Normal file
38
.drone.star
Normal file
@@ -0,0 +1,38 @@
|
||||
# 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")
|
||||
36
.drone/drone.bat
Executable file
36
.drone/drone.bat
Executable file
@@ -0,0 +1,36 @@
|
||||
@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 -j3
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/example -j3
|
||||
|
||||
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
|
||||
|
||||
REM not used
|
||||
|
||||
)
|
||||
199
.drone/drone.sh
Executable file
199
.drone/drone.sh
Executable file
@@ -0,0 +1,199 @@
|
||||
#!/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
|
||||
375
.github/workflows/ci.yml
vendored
Normal file
375
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,375 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- feature/**
|
||||
|
||||
env:
|
||||
UBSAN_OPTIONS: print_stacktrace=1
|
||||
|
||||
jobs:
|
||||
posix:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-4.8
|
||||
cxxstd: "11"
|
||||
os: ubuntu-18.04
|
||||
install: g++-4.8
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: g++-5
|
||||
- toolset: gcc-6
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: g++-6
|
||||
- toolset: gcc-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-8
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
install: g++-8
|
||||
- toolset: gcc-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: gcc-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-10
|
||||
- toolset: gcc-11
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-11
|
||||
- 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-18.04
|
||||
install: clang-3.9
|
||||
- toolset: clang
|
||||
compiler: clang++-4.0
|
||||
cxxstd: "11,14"
|
||||
os: ubuntu-18.04
|
||||
install: clang-4.0
|
||||
- toolset: clang
|
||||
compiler: clang++-5.0
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
install: clang-5.0
|
||||
- toolset: clang
|
||||
compiler: clang++-6.0
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
install: clang-6.0
|
||||
- toolset: clang
|
||||
compiler: clang++-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.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-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt 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
|
||||
python 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
|
||||
|
||||
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@v2
|
||||
|
||||
- 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
|
||||
|
||||
posix-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt 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
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Use library with add_subdirectory
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt 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
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install
|
||||
|
||||
- name: Use the installed library
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt 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
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,4 +31,5 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ before_install:
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule update --init --merge
|
||||
- git remote set-branches --add origin $BOOST_BRANCH
|
||||
- git pull --recurse-submodules
|
||||
- git pull --recurse-submodules || true
|
||||
- git submodule update --init
|
||||
- git checkout $BOOST_BRANCH
|
||||
- git submodule foreach "git reset --quiet --hard; git clean -fxd"
|
||||
@@ -131,6 +131,6 @@ after_success:
|
||||
- coveralls-lcov coverals/coverage.info
|
||||
|
||||
after_script:
|
||||
- curl -s https://report.ci/upload.py | python - --name="$BADGE test run"
|
||||
- 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"
|
||||
|
||||
36
CMakeLists.txt
Normal file
36
CMakeLists.txt
Normal file
@@ -0,0 +1,36 @@
|
||||
# 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 INTERFACE)
|
||||
add_library(Boost::process ALIAS boost_process)
|
||||
|
||||
target_include_directories(boost_process INTERFACE include)
|
||||
target_link_libraries(boost_process
|
||||
INTERFACE
|
||||
Boost::algorithm
|
||||
Boost::asio
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::filesystem
|
||||
Boost::fusion
|
||||
Boost::iterator
|
||||
Boost::move
|
||||
Boost::optional
|
||||
Boost::system
|
||||
Boost::tokenizer
|
||||
Boost::type_index
|
||||
Boost::winapi
|
||||
)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
|
||||
endif()
|
||||
|
||||
17
README.md
17
README.md
@@ -1,18 +1,21 @@
|
||||
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
|
||||
# [Boost Process (Boost.Process)](https://github.com/boostorg/process)
|
||||
|
||||
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
|
||||
|
||||
### Test results
|
||||
|
||||
Branches | Linux | OSX | Windows | Code coverage | Matrix |
|
||||
----------------|-------|-----|---------| ------------- |--------|
|
||||
Develop: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=linux) | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=osx) | [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/develop) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=windows) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) | [](http://www.boost.org/development/tests/develop/developer/process.html)
|
||||
Master: | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=linux) | [](https://travis-ci.org/klemens-morgenstern/boost-process) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=osx) | [](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) [](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=windows) | [](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) | [](http://www.boost.org/development/tests/master/developer/process.html)
|
||||
| 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) |
|
||||
|
||||
|
||||
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
|
||||
|
||||
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
|
||||
|
||||
|
||||
[Open Issues](https://github.com/boostorg/process/issues)
|
||||
|
||||
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
|
||||
|
||||
### 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.
|
||||
|
||||
@@ -24,12 +24,13 @@ generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
|
||||
xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ;
|
||||
xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ;
|
||||
|
||||
path-constant INCLUDES : ../../.. ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
../../../boost/process.hpp
|
||||
[ glob ../../../boost/process/*.hpp ]
|
||||
:
|
||||
$(INCLUDES)/boost/process.hpp
|
||||
[ glob $(INCLUDES)/boost/process/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=YES
|
||||
@@ -42,11 +43,49 @@ doxygen autodoc
|
||||
|
||||
|
||||
|
||||
doxygen reference_v2
|
||||
:
|
||||
$(INCLUDES)/boost/process/v2.hpp
|
||||
[ glob $(INCLUDES)/boost/process/v2/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>PROJECT_NAME="Process V2"
|
||||
<doxygen:param>PROJECT_BRIEF="The process library"
|
||||
<doxygen:param>MACRO_EXPANSION=YES
|
||||
<doxygen:param>EXPAND_ONLY_PREDEF=YES
|
||||
<doxygen:param>"PREDEFINED=\\
|
||||
GENERATING_DOCUMENTATION=1 \\
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE=boost::asio \\
|
||||
\"BOOST_PROCESS_V2_BEGIN_NAMESPACE=namespace boost { namespace process { namespace v2 { \" \\
|
||||
\"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\
|
||||
BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\
|
||||
BOOST_PROCESS_V2_DECL \\
|
||||
BOOST_PROCESS_V2_SOURCE \\
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\
|
||||
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\
|
||||
BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\
|
||||
BOOST_CONSTEXPR=constexpr \\
|
||||
BOOST_CXX14_CONSTEXPR=constexpr \\
|
||||
BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]]
|
||||
"
|
||||
<doxygen.doxproc.id>reference_v2
|
||||
<doxygen:param>SHOW_USED_FILES=NO
|
||||
<doxygen:param>SHOW_FILES=NO
|
||||
<doxygen:param>SHOW_NAMESPACES=YES
|
||||
<doxygen:param>CLASS_DIAGRAMS=NO
|
||||
<doxygen:param>SORT_MEMBERS_CTORS_1ST=YES
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=NO
|
||||
<xsl:path>.
|
||||
;
|
||||
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
process.qbk
|
||||
:
|
||||
<dependency>autodoc
|
||||
<dependency>reference_v2
|
||||
<dependency>images
|
||||
<dependency>images_glob
|
||||
<xsl:param>boost.root=../../../..
|
||||
|
||||
@@ -8,4 +8,6 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
|
||||
|
||||
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]
|
||||
|
||||
@@ -16,11 +16,11 @@ In that it is different than other facilities (like sockets) and provides anothe
|
||||
Pipes are typically used for interprocess communication. The main reason is, that pipes can be directly assigned to the process stdio, i.e. stderr, stdin and stdout.
|
||||
Additionally, half of the pipe can be inherited to the child process and closed in the father process. This will cause the pipe to be broken when the child process exits.
|
||||
|
||||
Though please note, that if the the same thread reads and write to a pipe, it will only talk to itself.
|
||||
Though please note, that if the same thread reads and writes to a pipe, it will only talk to itself.
|
||||
|
||||
[section:anonymous Anonymous Pipes]
|
||||
|
||||
The usual type of pipes, are the anonymous ones. Since the have no name,
|
||||
The most common pipes are anonymous. Since they have no name,
|
||||
a handle to them can only be obtained from duplicating either handle.
|
||||
|
||||
In this library the following functions are used for the creation of unnamed pipes:
|
||||
@@ -57,12 +57,12 @@ Every process is identified by a unique number[footnote it is unique as long as
|
||||
|
||||
[section:exit_code Exit code]
|
||||
A process will return an integer value indicating whether it was successful. On posix
|
||||
there are more codes associated with that, but not so on windows. Therefore there is not such encoding currently in the library.
|
||||
there are more codes associated with that, but not so on windows. Therefore there is no such encoding currently in the library.
|
||||
However an exit code of zero means the process was successful, while one different than zero indicates an error.
|
||||
[endsect]
|
||||
|
||||
[section:termination Termination]
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to so and wait, and just terminate the process without conditions.
|
||||
Processes can also be forced to exit. There are two ways to do this, signal the process to do so and wait, and just terminate the process without conditions.
|
||||
|
||||
Usually the first approach is to signal an exit request, but windows - unlike posix - does not provide a consistent way to do this. Hence this is not part of the
|
||||
library and only the hard terminate is.
|
||||
@@ -79,4 +79,4 @@ The environment is a map of variables local to every process. The most significa
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[section:design Design Rationale]
|
||||
[section Scope]
|
||||
This library is meant to give an wrapper around the different OS-specific methods
|
||||
This library is meant to give a 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]
|
||||
[*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.
|
||||
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.
|
||||
|
||||
@@ -33,7 +33,7 @@ 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
|
||||
In the following section the available 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!
|
||||
@@ -54,7 +54,7 @@ interpret each string as an argument.
|
||||
]
|
||||
|
||||
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:
|
||||
several strings will yield a exe-args interpretation. Both versions can be set explicitly:
|
||||
|
||||
```
|
||||
system("grep -c false /etc/passwd"); //cmd style
|
||||
@@ -65,7 +65,7 @@ system(exe="grep", args={"-c", "false", "/etc/passwd"}); //exe-/args-
|
||||
```
|
||||
|
||||
[note If a '"' sign is used in the argument style, it will be passed as part of the argument.
|
||||
If the same effect it wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
If the same effect is wanted with the cmd syntax, it ought to be escaped, i.e. '\\\"'. ]
|
||||
[note The `PATH` variable will automatically be searched in the command style,
|
||||
but the one of the launching process, not the one passed to the child process.]
|
||||
[endsect]
|
||||
|
||||
@@ -15,14 +15,14 @@ To extend the library, the header [headerref boost/process/extend.hpp extend] is
|
||||
|
||||
It only provides the explicit style for custom properties, but no implicit style.
|
||||
|
||||
What this means is, that a custom initializer can be implemented, a reference to which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::extend::handler] it will be regarded as a initializer and thus directly put into the sequence
|
||||
What this means is, that a custom initializer can be implemented, a reference which can be passed to one of the launching functions.
|
||||
If a class inherits [classref boost::process::extend::handler] it will be regarded as an initializer and thus directly put into the sequence
|
||||
the executor gets passed.
|
||||
|
||||
[section:structure Structure]
|
||||
|
||||
The executor calls different handlers of the initializers during the process launch.
|
||||
The basic structure is consists of three functions, as given below:
|
||||
The basic structure consists of three functions, as given below:
|
||||
|
||||
* [globalref boost::process::extend::on_setup on_setup]
|
||||
* [globalref boost::process::extend::on_error on_error]
|
||||
@@ -53,7 +53,7 @@ namespace ex = bp::extend;
|
||||
__child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" << std::endl;});
|
||||
```
|
||||
|
||||
Considering that lambda can also capture values, data can easily be shared between handlers.
|
||||
Considering that lambdas can also capture values, data can easily be shared between handlers.
|
||||
|
||||
To see which members the executor has, refer to [classref boost::process::extend::windows_executor windows_executor]
|
||||
and [classref boost::process::extend::posix_executor posix_executor].
|
||||
@@ -86,7 +86,7 @@ __child__ c("foo", hello_world());
|
||||
|
||||
[note The implementation is done via overloading, not overriding.]
|
||||
|
||||
Every handler not implemented dafaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
|
||||
Every handler not implemented defaults to [classref boost::process::extend::handler handler], where an empty handler is defined for each event.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -100,7 +100,7 @@ this functionality is also available for extensions. If the class needs the __io
|
||||
```
|
||||
struct async_foo : __handler__, __require_io_context__
|
||||
{
|
||||
tempalte<typename Executor>
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
__io_context__ & ios = __get_io_context__(exec.seq); //gives us a reference and a compiler error if not present.
|
||||
@@ -139,10 +139,10 @@ struct async_bar : __handler, __async_handler__
|
||||
|
||||
[section:error Error handling]
|
||||
|
||||
If an error occurs in the initializers it shall be told to the executor and not handles directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the the executor
|
||||
If an error occurs in the initializers it shall be told to the executor and not handled directly. This is because
|
||||
the behaviour can be changed through arguments passed to the launching function. Hence the executor
|
||||
has the function `set_error`, which takes an [@http://en.cppreference.com/w/cpp/error/error_code std::error_code] and a string.
|
||||
Depending on the cofiguration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
Depending on the configuration of the executor, this may either throw, set an internal `error_code`, or do nothing.
|
||||
|
||||
So let's take a simple example, where we set a randomly chosen `error_code`.
|
||||
|
||||
@@ -202,8 +202,8 @@ struct hello_exe : __handler__
|
||||
};
|
||||
```
|
||||
|
||||
So given our example, the definitions with the non-native exectur are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement systems-specific code without using the preprocessor.
|
||||
So given our example, the definitions with the non-native executor are still a template so that they will not be evaluated if not used. Hence this provides a
|
||||
way to implement system-specific code without using the preprocessor.
|
||||
|
||||
[note If you only write a partial implementation, e.g. only for __posix_executor__, the other variants will default to __handler__].
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ while (is >> file)
|
||||
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
|
||||
[note It is not possible to use automatic 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:
|
||||
@@ -64,7 +64,7 @@ while (c.running())
|
||||
}
|
||||
```
|
||||
|
||||
It is therefore highly recommended that you use the asynchronous api if you are
|
||||
It is therefore highly recommended that you use the asynchronous API if you are
|
||||
not absolutely sure how the output will look.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
]
|
||||
]
|
||||
|
||||
[note [link process.v2 Process V2] is available as experimental]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include concepts.qbk]
|
||||
[include tutorial.qbk]
|
||||
@@ -19,3 +21,4 @@
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[include acknowledgements.qbk]
|
||||
[include v2.qbk]
|
||||
@@ -30,7 +30,7 @@
|
||||
[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:deadlock :environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
|
||||
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
|
||||
|
||||
@@ -68,12 +68,12 @@ namespace bp = boost::process; //we will assume this for all further examples
|
||||
int result = bp::system("g++ main.cpp");
|
||||
```
|
||||
|
||||
If a single string (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
If a single string is given (or the explicit form bp::cmd), it will be interpreted as a command line.
|
||||
That will cause the execution function to search the `PATH` variable to find the executable.
|
||||
The alternative is the `exe-args` style, where the first string will be interpreted as a filename (including the path),
|
||||
and the rest as arguments passed to said function.
|
||||
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here]]
|
||||
[note For more details on the `cmd`/`exe-args` style look [link boost_process.design.arg_cmd_style here].]
|
||||
|
||||
So as a first step, we'll use the `exe-args` style.
|
||||
|
||||
@@ -82,10 +82,10 @@ int result = bp::system("/usr/bin/g++", "main.cpp");
|
||||
```
|
||||
|
||||
With that syntax we still have "g++" hard-coded, so let's assume we get the string
|
||||
from an external source as `boost::filesystem::path`, we can do this too.
|
||||
from an external source as `boost::process::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
boost::process::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
@@ -93,7 +93,7 @@ Now we might want to find the `g++` executable in the `PATH`-variable, as the `c
|
||||
`Boost.process` provides a function to this end: bp::search_path.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
|
||||
boost::process::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
@@ -141,7 +141,7 @@ 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__]
|
||||
[note You can also wait for a time span or 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]
|
||||
@@ -217,7 +217,7 @@ std::vector<std::string> read_outline(std::string & file)
|
||||
What this does is redirect the `stdout` of the process into a pipe and we read this
|
||||
synchronously.
|
||||
|
||||
[note You can do the same thing with [globalref boost::process::std_err std_err]]
|
||||
[note You can do the same thing with [globalref boost::process::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
|
||||
@@ -246,7 +246,7 @@ std::vector<std::string> read_demangled_outline(const std::string & file)
|
||||
|
||||
std::vector<std::string> outline;
|
||||
|
||||
//we just use the same pipe, so the
|
||||
//we just use the same pipe, so the output of nm is directly passed as input to c++filt
|
||||
bp::child nm(bp::search_path("nm"), file, bp::std_out > p);
|
||||
bp::child filt(bp::search_path("c++filt"), bp::std_in < p, bp::std_out > is);
|
||||
|
||||
@@ -270,7 +270,7 @@ If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boos
|
||||
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,
|
||||
Now we get back to our compiling example. For `nm` we might analyze the output line by line,
|
||||
but the compiler output will just be put into one large buffer.
|
||||
|
||||
With [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] this is what it looks like.
|
||||
@@ -290,7 +290,7 @@ ios.run();
|
||||
int result = c.exit_code();
|
||||
```
|
||||
|
||||
To make it easier, boost.process provides simpler interface for that, so that the buffer can be passed directly,
|
||||
To make it easier, boost.process provides a simpler interface for that, so that the buffer can be passed directly,
|
||||
provided we also pass a reference to an io_service.
|
||||
|
||||
```
|
||||
@@ -304,7 +304,7 @@ int result = c.exit_code();
|
||||
```
|
||||
|
||||
[note Passing an instance of io_service to the launching function automatically cause it to wait asynchronously for the exit, so no call of
|
||||
[memberref boost::process::child::wait wait] is needed]
|
||||
[memberref boost::process::child::wait wait] is needed.]
|
||||
|
||||
To make it even easier, you can use [@http://en.cppreference.com/w/cpp/thread/future std::future] for asynchronous operations
|
||||
(you will still need to pass a reference to a io_service) to the launching function, unless you use bp::system or bp::async_system.
|
||||
@@ -331,7 +331,7 @@ auto err = data.get();
|
||||
[endsect]
|
||||
[section:group Groups]
|
||||
|
||||
When launching several processes, processes can be grouped together.
|
||||
When launching several processes, they can be grouped together.
|
||||
This will also apply for a child process, that launches other processes,
|
||||
if they do not modify the group membership. E.g. if you call `make` which
|
||||
launches other processes and call terminate on it,
|
||||
@@ -342,7 +342,7 @@ The two main reasons to use groups are:
|
||||
# Being able to terminate child processes of the child process
|
||||
# Grouping several processes into one, just so they can be terminated at once
|
||||
|
||||
If we have program like `make`, which does launch its own child processes,
|
||||
If we have a program like `make`, which does launch its own child processes,
|
||||
a call of child_terminate might not suffice. I.e. if we have a makefile launching `gcc`
|
||||
and use the following code, the `gcc` process will still run afterwards:
|
||||
|
||||
@@ -412,14 +412,14 @@ bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::env env] property, which the example as following:
|
||||
[globalref boost::process::env env] property, which can be used in the example as following:
|
||||
|
||||
```
|
||||
bp::system("stuff", bp::env["VALUE_1"]="foo", bp::env["VALUE_2"]+={"bar1", "bar2"});
|
||||
|
||||
```
|
||||
|
||||
Please see to the [headerref boost/process/environment.hpp reference] for more information.
|
||||
Please see the [headerref boost/process/environment.hpp reference] for more information.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
11
doc/v2.qbk
Normal file
11
doc/v2.qbk
Normal file
@@ -0,0 +1,11 @@
|
||||
[section:v2 Process V2]
|
||||
|
||||
[include v2/introduction.qbk]
|
||||
[include v2/quickstart.qbk]
|
||||
[include v2/launcher.qbk]
|
||||
[include v2/start_dir.qbk]
|
||||
[include v2/stdio.qbk]
|
||||
[include v2/env.qbk]
|
||||
[xinclude reference_v2.xml]
|
||||
|
||||
[endsect]
|
||||
48
doc/v2/env.qbk
Normal file
48
doc/v2/env.qbk
Normal file
@@ -0,0 +1,48 @@
|
||||
[section:env 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 recommented 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.
|
||||
|
||||
```
|
||||
// search in the current environment
|
||||
auto exe = environment::find_executable("g++");
|
||||
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"}
|
||||
{"PATH", {"/bin", "/usr/bin"}
|
||||
};
|
||||
|
||||
auto other_exe = environment::find_executable("g++", my_env);
|
||||
```
|
||||
|
||||
[section:process_env Subprocess environment]
|
||||
|
||||
The subprocess environment assignment follows the same constraints:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"}
|
||||
{"PATH", {"/bin", "/usr/bin"}
|
||||
};
|
||||
auto exe = 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));
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
94
doc/v2/introduction.qbk
Normal file
94
doc/v2/introduction.qbk
Normal file
@@ -0,0 +1,94 @@
|
||||
[section:introduction Introduction]
|
||||
|
||||
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
|
||||
|
||||
[section:simplified Simplified Interface]
|
||||
|
||||
In process v1 one can define partial settings in the constructor of the process,
|
||||
which has lead to a small DSL.
|
||||
|
||||
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:
|
||||
|
||||
extern std::unordered_map<std::string, std::string> my_env;
|
||||
extern asio::io_context ctx;
|
||||
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
|
||||
|
||||
Every initializer adresses one logical compoent (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.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pidfd_open pidfd_open]
|
||||
|
||||
Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a
|
||||
file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
|
||||
FreeBSD has a similar feature with `pdfork` which is also supported, while 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.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:asio 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.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:unreliable 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 not safely be implemented with an async_wait + timeout.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:utf8 UTF-8]
|
||||
|
||||
["UTF-8 or GTFO]--Vinnie Falco
|
||||
|
||||
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:src Separate compilation]
|
||||
|
||||
Boost.process v2 supports separate compilation similar to other boost libraries.
|
||||
It can be achieved by defining `BOOST_PROCESS_V2_SEPARATE_COMPILATION` and including
|
||||
`<process/v2/src.hpp>` in a single compile unit.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:limit_fd 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.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
128
doc/v2/launcher.qbk
Normal file
128
doc/v2/launcher.qbk
Normal file
@@ -0,0 +1,128 @@
|
||||
[section:launchers 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.
|
||||
|
||||
[table:launchers Launcher overview
|
||||
[[Name] [Summary] [Default on] [Available on]]
|
||||
[[`windows::default_launcher`] [Launcher using `CreateProcessW`] [windows] [windows]]
|
||||
[[`windows::as_user_launcher`] [Launcher using `CreateProcessAsUserW`] [] [windows]]
|
||||
[[`windows::with_logon_launcher`] [Launcher using `CreateProcessWithLogonW`] [] [windows]]
|
||||
[[`windows::with_token_launcher`] [Launcher using `CreateProcessWithTokenW`] [] [windows]]
|
||||
[[`posix::default_launcher`] [Launcher using fork & an error pipe] [most of posix] [posix]]
|
||||
[[`posix::fork_and_forget`] [Launcher using fork without error pipe] [] [posix]]
|
||||
[[`posix::pdfork_launcher`] [Launcher using pdfork with an error pipe] [FreeBSD] [FreeBSD]]
|
||||
[[`posix::vfork_launcher`] [Launcher using vfork] [] [posix]]
|
||||
]
|
||||
|
||||
A launcher is invoked through the call operator.
|
||||
|
||||
```
|
||||
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
|
||||
asio::io_context ctx;
|
||||
boost::system::eror_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.
|
||||
|
||||
[section:linux Linux Launchers]
|
||||
|
||||
The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
|
||||
|
||||
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.
|
||||
|
||||
```
|
||||
struct custom_initalizer
|
||||
{
|
||||
// functions called from the parent process:
|
||||
|
||||
|
||||
// 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 occured 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 occured when forking, in addtion 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:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_success.svg"/>
|
||||
'''
|
||||
|
||||
The call sequence when fork fails:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_fork_err.svg"/>
|
||||
'''
|
||||
|
||||
The call sequence when exec fails:
|
||||
'''
|
||||
<imagedata fileref="boost_process/posix_exec_err.svg"/>
|
||||
'''
|
||||
|
||||
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:windows Windows Launchers]
|
||||
|
||||
Windows launchers are pretty streight forward, they will call the following functions on the initializer if present.
|
||||
|
||||
```
|
||||
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 occured 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);
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
[note All the additional launchers for windows inherit `default_launcher`]
|
||||
|
||||
The call sequence is as follows:
|
||||
'''
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
'''
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
124
doc/v2/quickstart.qbk
Normal file
124
doc/v2/quickstart.qbk
Normal file
@@ -0,0 +1,124 @@
|
||||
[section:quickstart 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
|
||||
|
||||
```
|
||||
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
|
||||
asio::io_context ctx;
|
||||
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
|
||||
```
|
||||
|
||||
|
||||
The started process can then be awaited or terminated.
|
||||
|
||||
[section:lifetime 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()`.
|
||||
|
||||
```
|
||||
process proc("/bin/ls", {});
|
||||
assert(proc.wait() == 0);
|
||||
```
|
||||
|
||||
The normal exit-code is what the subprocess returned from `main`;
|
||||
posix will however add addtional 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.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:signal Signalling the subprocess]
|
||||
|
||||
The parent process can signal the subprocess demaning certain actions.
|
||||
|
||||
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||||
This is the only reliable & portable way to end a subprocess.
|
||||
|
||||
```
|
||||
process proc("/bin/totally-not-a-virus", {});
|
||||
proc.terminate();
|
||||
```
|
||||
|
||||
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
|
||||
which the subprocess might ignore.
|
||||
|
||||
```
|
||||
process proc("/bin/bash", {});
|
||||
proc.request_exit();
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
|
||||
interpret as a signal to shutdown.
|
||||
|
||||
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
|
||||
|
||||
```
|
||||
process proc("/usr/bin/addr2line", {});
|
||||
proc.request_exit();
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:execute Execute functions]
|
||||
|
||||
Process v2 provides `execute` and `async_execute` functons that can be used for managed executions.
|
||||
|
||||
```
|
||||
assert(execute(process("/bin/ls", {}) == 0));
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::steady_timer timout{ctx, std::chrono::seconds(10)};
|
||||
|
||||
asio::cancellation_signal sig;
|
||||
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
|
||||
asio::bind_cancellation_slot(sig.slot(),
|
||||
[&](error_code ec, int exit_code)
|
||||
{
|
||||
timeout.cancel(); // we're done earlier
|
||||
}));
|
||||
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
if (ec) // we were cancelled, do nothing
|
||||
return ;
|
||||
sig.emit(asio::cancellation_type::partial);
|
||||
// request exit first, but terminate after another 10 sec
|
||||
timeout.expires_after(std::chrono::seconds(10));
|
||||
timeout.async_wait(
|
||||
[&](error_code ec)
|
||||
{
|
||||
if (!ec)
|
||||
sig.emit(asio::cancellation_type::terminal);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
16
doc/v2/start_dir.qbk
Normal file
16
doc/v2/start_dir.qbk
Normal file
@@ -0,0 +1,16 @@
|
||||
[section:start_dir process_start_dir]
|
||||
|
||||
The easier initializer to use is `process_start_dir`:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
process ls(ctx, "/ls", {}, process_start_dir("/home"));
|
||||
ls.wait();
|
||||
```
|
||||
|
||||
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.]
|
||||
|
||||
|
||||
[endsect]
|
||||
89
doc/v2/stdio.qbk
Normal file
89
doc/v2/stdio.qbk
Normal file
@@ -0,0 +1,89 @@
|
||||
[section:stdio 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.
|
||||
|
||||
[section:pipe Pipe]
|
||||
|
||||
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:
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe rp;
|
||||
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
|
||||
std::string output;
|
||||
|
||||
system::error_code ec;
|
||||
rp.read(asio::dynamic_buffer(output), ec);
|
||||
assert(ec == asio::eof);
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
readable pipes can be assigned to `out` an `err``, while writable_pipes can be assigned to `in`.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:file `FILE*`]
|
||||
|
||||
`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used:
|
||||
|
||||
```
|
||||
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();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:null `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.
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
// ignore stderr
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr});
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:native_handle `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` returning that native handle type is valid, too.
|
||||
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
// ignore stderr
|
||||
asio::ip::tcp::socket sock{ctx};
|
||||
connect_my_socket(sock);
|
||||
process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr});
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:popen 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.
|
||||
|
||||
```
|
||||
popen proc(executor, "/usr/bin/addr2line, {argv[0]});
|
||||
asio::write(proc, asio::buffer("main\n"));
|
||||
std::string line;
|
||||
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -10,6 +10,9 @@
|
||||
//[intro
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
using namespace boost::process;
|
||||
|
||||
int main()
|
||||
|
||||
@@ -22,7 +22,7 @@ int main()
|
||||
bp::std_in < bp::null //null in
|
||||
);
|
||||
|
||||
boost::filesystem::path p = "input.txt";
|
||||
boost::process::filesystem::path p = "input.txt";
|
||||
|
||||
bp::system(
|
||||
"test.exe",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
@@ -19,9 +19,9 @@ int main()
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
|
||||
boost::filesystem::path exe = "test.exe";
|
||||
boost::process::filesystem::path exe = "test.exe";
|
||||
bp::system(
|
||||
boost::filesystem::absolute(exe),
|
||||
boost::process::filesystem::absolute(exe),
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
}
|
||||
|
||||
17
example/v2/Jamfile.jam
Normal file
17
example/v2/Jamfile.jam
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright (c) 2022 Klemens 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)
|
||||
|
||||
project : requirements
|
||||
<include>../../..
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
;
|
||||
|
||||
import testing ;
|
||||
|
||||
alias filesystem : /boost//filesystem : <link>static ;
|
||||
|
||||
exe intro : intro.cpp filesystem ;
|
||||
exe intro_popen : intro_popen.cpp filesystem ;
|
||||
39
example/v2/intro.cpp
Normal file
39
example/v2/intro.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
//
|
||||
// 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)
|
||||
|
||||
//[intro
|
||||
#include <boost/process/v2.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::v2;
|
||||
namespace asio = boost::asio;
|
||||
|
||||
|
||||
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}};
|
||||
|
||||
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;
|
||||
|
||||
c.wait();
|
||||
}
|
||||
//]
|
||||
36
example/v2/intro_popen.cpp
Normal file
36
example/v2/intro_popen.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
//
|
||||
// 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)
|
||||
|
||||
//[intro
|
||||
#include <boost/process/v2.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::v2;
|
||||
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);
|
||||
|
||||
std::cout << "Gcc version: '" << line << "'" << std::endl;
|
||||
|
||||
c.wait();
|
||||
}
|
||||
//]
|
||||
@@ -8,6 +8,7 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
#include <boost/process/windows.hpp>
|
||||
#include <iostream>
|
||||
|
||||
@@ -22,9 +23,9 @@ int main()
|
||||
|
||||
|
||||
bp::system("test.exe",
|
||||
bp::on_setup([](auto &e)
|
||||
bp::extend::on_setup([](auto &e)
|
||||
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
|
||||
bp::on_error([](auto&, const std::error_code & ec)
|
||||
bp::extend::on_error([](auto&, const std::error_code & ec)
|
||||
{ std::cerr << ec.message() << std::endl; })
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ struct args_
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(range.begin(), range.end());
|
||||
return arg_setter_<char, true>(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, true>(range.begin(), range.end());
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator()(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char>(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
|
||||
{
|
||||
@@ -158,12 +158,12 @@ struct args_
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
return arg_setter_<char, false>(range.begin(), range.end());
|
||||
}
|
||||
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, true>(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, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator()(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t>(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
|
||||
{
|
||||
@@ -183,7 +183,7 @@ struct args_
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -109,10 +109,10 @@ with `function` being a callable object with the signature `(int, const std::err
|
||||
\code{.cpp}
|
||||
io_context ios;
|
||||
|
||||
child c("ls", on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
std::future<int> exit_code;
|
||||
chlid c2("ls", on_exit=exit_code);
|
||||
chlid c2("ls", ios, on_exit=exit_code);
|
||||
|
||||
\endcode
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace boost { namespace process {
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
|
||||
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
|
||||
/** Class implementing an asnychronous I/O-Object for use with boost.asio.
|
||||
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
|
||||
* boost::asio::posix::stream_descriptor.
|
||||
*
|
||||
@@ -47,6 +47,8 @@ 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.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
|
||||
@@ -38,12 +38,11 @@ namespace process {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ExitHandler>
|
||||
template<typename Handler>
|
||||
struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
{
|
||||
boost::asio::io_context & ios;
|
||||
boost::asio::async_completion<
|
||||
ExitHandler, void(boost::system::error_code, int)> init;
|
||||
Handler handler;
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
bool errored = false;
|
||||
@@ -52,9 +51,8 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
template<typename ExitHandler_>
|
||||
async_system_handler(
|
||||
boost::asio::io_context & ios,
|
||||
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
|
||||
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -64,21 +62,15 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
#if defined(BOOST_POSIX_API)
|
||||
errored = true;
|
||||
#endif
|
||||
auto & h = init.completion_handler;
|
||||
auto h = std::make_shared<Handler>(std::move(handler));
|
||||
boost::asio::post(
|
||||
ios.get_executor(),
|
||||
[h, ec]() mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
get_result()
|
||||
{
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
@@ -86,10 +78,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
if (errored)
|
||||
return [](int , const std::error_code &){};
|
||||
#endif
|
||||
auto & h = init.completion_handler;
|
||||
auto h = std::make_shared<Handler>(std::move(handler));
|
||||
return [h](int exit_code, const std::error_code & ec) mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -120,21 +112,36 @@ inline boost::process::detail::dummy
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct async_system_init_op
|
||||
{
|
||||
|
||||
template<typename Handler, typename ... Args>
|
||||
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
|
||||
{
|
||||
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
|
||||
{
|
||||
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
|
||||
|
||||
|
||||
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
|
||||
has_err_handling;
|
||||
|
||||
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
|
||||
|
||||
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
|
||||
return async_h.get_result();
|
||||
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
|
||||
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() {}
|
||||
constexpr cmd_() = default;
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const Char *s) const
|
||||
|
||||
@@ -168,7 +168,7 @@ struct exe_builder
|
||||
string_type exe;
|
||||
std::vector<string_type> args;
|
||||
|
||||
void operator()(const boost::filesystem::path & data)
|
||||
void operator()(const boost::process::filesystem::path & data)
|
||||
{
|
||||
not_cmd = true;
|
||||
if (exe.empty())
|
||||
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
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)),
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
child() {}
|
||||
child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
|
||||
child& operator=(const child&) = delete;
|
||||
child& operator=(child && lhs)
|
||||
{
|
||||
@@ -125,7 +125,10 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
}
|
||||
|
||||
#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;
|
||||
@@ -135,6 +138,7 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -142,6 +146,7 @@ public:
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
@@ -178,13 +183,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
if (!_exited())
|
||||
@@ -197,7 +205,7 @@ public:
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -114,6 +114,8 @@ template<typename Char> constexpr Char space_sign();
|
||||
template<> constexpr char space_sign<char> () {return ' '; }
|
||||
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}}
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
@@ -20,39 +21,19 @@ template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
class io_context;
|
||||
|
||||
class executor;
|
||||
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
|
||||
class signal_set_service;
|
||||
template <typename SignalSetService>
|
||||
|
||||
class basic_signal_set;
|
||||
typedef basic_signal_set<signal_set_service> signal_set;
|
||||
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
template <typename Executor>
|
||||
class basic_signal_set;
|
||||
typedef basic_signal_set<executor> signal_set;
|
||||
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
typedef basic_signal_set<any_io_executor> signal_set;
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace posix {
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
|
||||
class stream_descriptor_service;
|
||||
|
||||
template <typename StreamDesscriptorService>
|
||||
class basic_stream_descriptor;
|
||||
typedef basic_stream_descriptor<stream_descriptor_service> stream_descriptor;
|
||||
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
template <typename Executor>
|
||||
class basic_stream_descriptor;
|
||||
typedef basic_stream_descriptor<executor> stream_descriptor;
|
||||
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
|
||||
|
||||
} //posix
|
||||
} //asio
|
||||
|
||||
@@ -145,8 +145,11 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
{
|
||||
std::istream is (buffer_.get());
|
||||
Type arg;
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
if (buffer_->size() > 0)
|
||||
{
|
||||
arg.resize(buffer_->size());
|
||||
is.read(&*arg.begin(), buffer_->size());
|
||||
}
|
||||
promise_->set_value(std::move(arg));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -23,6 +23,12 @@ class async_pipe
|
||||
public:
|
||||
typedef int native_handle_type;
|
||||
typedef ::boost::asio::posix::stream_descriptor handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
executor_type get_executor()
|
||||
{
|
||||
return _source.get_executor();
|
||||
}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
|
||||
|
||||
@@ -44,8 +50,8 @@ public:
|
||||
inline async_pipe(const async_pipe& lhs);
|
||||
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
|
||||
{
|
||||
lhs._source.assign (-1);
|
||||
lhs._sink .assign (-1);
|
||||
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
|
||||
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
@@ -70,10 +76,8 @@ public:
|
||||
|
||||
~async_pipe()
|
||||
{
|
||||
if (_sink .native_handle() != -1)
|
||||
::close(_sink.native_handle());
|
||||
if (_source.native_handle() != -1)
|
||||
::close(_source.native_handle());
|
||||
boost::system::error_code ec;
|
||||
close(ec);
|
||||
}
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
|
||||
@@ -139,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::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(
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define BOOST_PROCESS_POSIX_PIPE_HPP
|
||||
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/process/detail/posix/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <array>
|
||||
@@ -82,18 +82,26 @@ public:
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
auto write_len = ::write(_sink, data, count * sizeof(char_type));
|
||||
if (write_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type 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::detail::throw_last_error();
|
||||
}
|
||||
return write_len;
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
auto read_len = ::read(_source, data, count * sizeof(char_type));
|
||||
if (read_len == -1)
|
||||
::boost::process::detail::throw_last_error();
|
||||
|
||||
int_type read_len;
|
||||
while ((read_len = static_cast<int_type>(::read(_source, data, count * sizeof(char_type)))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
}
|
||||
return read_len;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ 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};}
|
||||
std::array<int, 2> get_used_handles() {return {{p1 != -1 ? p1 : p2, p2 != -1 ? p2 : p1}};}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
{
|
||||
_buffer = _load();
|
||||
_impl = _load_var(_buffer);
|
||||
_env_impl = _impl.data();
|
||||
}
|
||||
|
||||
string_type get(const pointer_type id) { return get(string_type(id)); }
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
native_environment_impl & operator=(native_environment_impl && ) = default;
|
||||
native_handle_type _env_impl = _impl.data();
|
||||
|
||||
native_handle_type native_handle() const {return environ;}
|
||||
native_handle_type native_handle() const {return _env_impl;}
|
||||
};
|
||||
|
||||
template<>
|
||||
@@ -230,7 +231,7 @@ 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)
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
@@ -250,7 +251,7 @@ 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)
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
@@ -270,7 +271,7 @@ 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)
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
return false;
|
||||
@@ -294,7 +295,11 @@ std::vector<Char*> basic_environment_impl<Char>::_load_var(std::vector<std::basi
|
||||
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;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
@@ -149,15 +151,15 @@ class executor
|
||||
|
||||
int _pipe_sink = -1;
|
||||
|
||||
|
||||
void write_error(const std::error_code & ec, const char * msg)
|
||||
{
|
||||
//I am the child
|
||||
int len = ec.value();
|
||||
::write(_pipe_sink, &len, sizeof(int));
|
||||
const auto len = static_cast<int>(std::strlen(msg));
|
||||
int data[2] = {ec.value(), len + 1};
|
||||
|
||||
len = std::strlen(msg) + 1;
|
||||
::write(_pipe_sink, &len, sizeof(int));
|
||||
::write(_pipe_sink, msg, len);
|
||||
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
|
||||
boost::ignore_unused(::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_)
|
||||
@@ -273,14 +275,15 @@ class executor
|
||||
prepare_cmd_style_fn = exe;
|
||||
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
|
||||
{
|
||||
auto e = ::environ;
|
||||
while ((*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
const auto * e = ::environ;
|
||||
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if (e != nullptr)
|
||||
if ((e != nullptr) && (*e != nullptr))
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
boost::split(path, *e, boost::is_any_of(":"));
|
||||
//the beginning of the string contains "PATH="
|
||||
boost::split(path, (*e) + 5, boost::is_any_of(":"));
|
||||
|
||||
for (const std::string & pp : path)
|
||||
{
|
||||
@@ -325,6 +328,13 @@ 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>
|
||||
@@ -434,6 +444,8 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
}
|
||||
if (_ec)
|
||||
{
|
||||
//if an error occured we need to reap the child process
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
@@ -527,6 +539,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -23,7 +24,7 @@ struct file_descriptor
|
||||
|
||||
|
||||
file_descriptor() = default;
|
||||
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
|
||||
explicit file_descriptor(const boost::process::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
@@ -39,10 +40,22 @@ struct file_descriptor
|
||||
}
|
||||
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
file_descriptor(file_descriptor &&other)
|
||||
: _handle(boost::exchange(other._handle, -1))
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (_handle != -1)
|
||||
::close(_handle);
|
||||
_handle = boost::exchange(other._handle, -1);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, handle};
|
||||
return {{STDIN_FILENO, handle}};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -42,7 +42,7 @@ struct group_handle
|
||||
}
|
||||
|
||||
void add(handle_t proc)
|
||||
{
|
||||
{
|
||||
if (::setpgid(proc, grp))
|
||||
throw_last_error();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2106 Klemens D. Morgenstern
|
||||
// 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)
|
||||
|
||||
@@ -25,7 +25,7 @@ struct null_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
|
||||
std::array<int, 2> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source.handle()};
|
||||
return {{STDIN_FILENO, source.handle()}};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,26 +6,39 @@
|
||||
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup);
|
||||
|
||||
namespace posix {
|
||||
|
||||
struct on_exit_ : boost::process::detail::posix::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
|
||||
{
|
||||
return handler;
|
||||
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked);
|
||||
auto handler_ = this->handler;
|
||||
return
|
||||
[handler_, v](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler_(exit_code, ec);
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ struct pipe_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
{
|
||||
return {STDIN_FILENO, source, sink};
|
||||
return {{STDIN_FILENO, source, sink}};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@@ -20,15 +20,19 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline boost::filesystem::path search_path(
|
||||
const boost::filesystem::path &filename,
|
||||
const std::vector<boost::filesystem::path> &path)
|
||||
inline boost::process::filesystem::path search_path(
|
||||
const boost::process::filesystem::path &filename,
|
||||
const std::vector<boost::process::filesystem::path> &path)
|
||||
{
|
||||
for (const boost::filesystem::path & pp : path)
|
||||
for (const boost::process::filesystem::path & pp : path)
|
||||
{
|
||||
auto p = pp / filename;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(p, ec);
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(p, ec);
|
||||
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
inline boost::filesystem::path shell_path()
|
||||
inline boost::process::filesystem::path shell_path()
|
||||
{
|
||||
return "/bin/sh";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path shell_path(std::error_code &ec)
|
||||
inline boost::process::filesystem::path shell_path(std::error_code &ec)
|
||||
{
|
||||
ec.clear();
|
||||
return "/bin/sh";
|
||||
|
||||
@@ -15,15 +15,16 @@
|
||||
#include <signal.h>
|
||||
#include <functional>
|
||||
#include <sys/wait.h>
|
||||
#include <list>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
class sigchld_service : public boost::asio::detail::service_base<sigchld_service>
|
||||
{
|
||||
boost::asio::io_context::strand _strand{get_io_context()};
|
||||
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
|
||||
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
|
||||
|
||||
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
|
||||
inline void _handle_signal(const boost::system::error_code & ec);
|
||||
public:
|
||||
sigchld_service(boost::asio::io_context & io_context)
|
||||
@@ -48,9 +49,22 @@ public:
|
||||
int status;
|
||||
auto pid_res = ::waitpid(pid, &status, WNOHANG);
|
||||
if (pid_res < 0)
|
||||
h(-1, get_last_error());
|
||||
{
|
||||
auto ec = get_last_error();
|
||||
boost::asio::post(
|
||||
_strand,
|
||||
[pid_res, ec, h]
|
||||
{
|
||||
h(pid_res, ec);
|
||||
});
|
||||
}
|
||||
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
|
||||
h(status, {}); //successfully exited already
|
||||
boost::asio::post(
|
||||
_strand,
|
||||
[status, h]
|
||||
{
|
||||
h(status, {}); //successfully exited already
|
||||
});
|
||||
else //still running
|
||||
{
|
||||
if (_receivers.empty())
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
@@ -21,12 +22,12 @@ struct start_dir_init : handler_base_ext
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
start_dir_init(const string_type &s) : s_(s) {}
|
||||
start_dir_init(string_type s) : s_(std::move(s)) {}
|
||||
|
||||
template <class PosixExecutor>
|
||||
void on_exec_setup(PosixExecutor&) const
|
||||
{
|
||||
::chdir(s_.c_str());
|
||||
boost::ignore_unused(::chdir(s_.c_str()));
|
||||
}
|
||||
const string_type & str() const {return s_;}
|
||||
private:
|
||||
|
||||
@@ -27,7 +27,7 @@ inline void terminate(const child_handle &p, std::error_code &ec) noexcept
|
||||
ec.clear();
|
||||
|
||||
int status;
|
||||
::waitpid(p.pid, &status, WNOHANG); //just to clean it up
|
||||
::waitpid(p.pid, &status, 0); //should not be WNOHANG, since that would allow zombies.
|
||||
}
|
||||
|
||||
inline void terminate(const child_handle &p)
|
||||
|
||||
@@ -158,7 +158,7 @@ inline bool wait_until(
|
||||
{
|
||||
int res;
|
||||
::kill(pid, SIGKILL);
|
||||
::waitpid(pid, &res, WNOHANG);
|
||||
::waitpid(pid, &res, 0);
|
||||
}
|
||||
};
|
||||
child_cleaner_t child_cleaner{timeout_pid};
|
||||
|
||||
@@ -64,79 +64,9 @@ inline bool wait_until(
|
||||
bool timed_out = false;
|
||||
int ret;
|
||||
|
||||
#if defined(BOOST_POSIX_HAS_SIGTIMEDWAIT)
|
||||
auto get_timespec =
|
||||
+[](const Duration & dur)
|
||||
{
|
||||
::timespec ts;
|
||||
ts.tv_sec = std::chrono::duration_cast<std::chrono::seconds>(dur).count();
|
||||
ts.tv_nsec = std::chrono::duration_cast<std::chrono::nanoseconds>(dur).count() % 1000000000;
|
||||
return ts;
|
||||
};
|
||||
|
||||
::sigset_t sigset;
|
||||
|
||||
if (sigemptyset(&sigset) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
if (sigaddset(&sigset, SIGCHLD) != 0)
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ::sigaction old_sig;
|
||||
if (-1 == ::sigaction(SIGCHLD, nullptr, &old_sig))
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
auto ts = get_timespec(time_out - Clock::now());
|
||||
ret = ::sigtimedwait(&sigset, nullptr, &ts);
|
||||
errno = 0;
|
||||
if ((ret == SIGCHLD) && (old_sig.sa_handler != SIG_DFL) && (old_sig.sa_handler != SIG_IGN))
|
||||
old_sig.sa_handler(ret);
|
||||
|
||||
ret = ::waitpid(-p.grp, &siginfo.si_status, 0); //so in case it exited, we wanna reap it first
|
||||
if (ret == -1)
|
||||
{
|
||||
if ((errno == ECHILD) || (errno == ESRCH))
|
||||
{
|
||||
ec.clear();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = get_last_error();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//check if we're done ->
|
||||
ret = ::waitid(P_PGID, p.grp, &siginfo, WEXITED | WNOHANG);
|
||||
}
|
||||
while (((ret != -1) || ((errno != ECHILD) && (errno != ESRCH))) && !(timed_out = (Clock::now() > time_out)));
|
||||
|
||||
if (errno != ECHILD)
|
||||
{
|
||||
ec = boost::process::detail::get_last_error();
|
||||
return !timed_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
ec.clear();
|
||||
return true; //even if timed out, there are no child proccessess left
|
||||
}
|
||||
|
||||
#else
|
||||
::timespec sleep_interval;
|
||||
sleep_interval.tv_sec = 0;
|
||||
sleep_interval.tv_nsec = 1000000;
|
||||
sleep_interval.tv_nsec = 100000000;
|
||||
|
||||
|
||||
while (!(timed_out = (Clock::now() > time_out)))
|
||||
@@ -156,7 +86,6 @@ inline bool wait_until(
|
||||
::nanosleep(&sleep_interval, nullptr);
|
||||
}
|
||||
return !timed_out;
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
@@ -53,12 +53,12 @@ template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { type
|
||||
|
||||
template<> struct initializer_tag<shell_>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
|
||||
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
template<> struct initializer_tag<boost::filesystem::path>
|
||||
template<> struct initializer_tag<boost::process::filesystem::path>
|
||||
{
|
||||
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
|
||||
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
|
||||
};
|
||||
|
||||
template <typename Char>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/env.hpp>
|
||||
@@ -18,7 +20,7 @@ namespace boost { namespace process { namespace detail {
|
||||
|
||||
template<typename T> struct is_wchar_t : std::false_type {};
|
||||
|
||||
template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t>
|
||||
template<> struct is_wchar_t<boost::process::filesystem::path> : std::is_same<typename boost::process::filesystem::path::value_type, wchar_t>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ template<typename Executor>
|
||||
std::vector<::boost::process::detail::api::native_handle_type>
|
||||
get_used_handles(Executor &exec)
|
||||
{
|
||||
std::vector<::boost::process::detail::api::native_handle_type> res;
|
||||
std::vector<::boost::process::detail::api::native_handle_type> res = exec.get_used_handles();
|
||||
foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);});
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BOOST_PROCESS_DETAIL_WINDOWS_ASIO_FWD_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <boost/asio/ts/netfwd.hpp>
|
||||
|
||||
namespace boost { namespace asio {
|
||||
|
||||
@@ -19,43 +20,19 @@ template<typename Allocator>
|
||||
class basic_streambuf;
|
||||
|
||||
typedef basic_streambuf<std::allocator<char>> streambuf;
|
||||
class io_context;
|
||||
|
||||
class executor;
|
||||
|
||||
|
||||
template <typename Handler>
|
||||
class basic_yield_context;
|
||||
|
||||
namespace windows {
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
|
||||
class stream_handle_service;
|
||||
|
||||
template <typename StreamHandleService>
|
||||
class basic_stream_handle;
|
||||
|
||||
typedef basic_stream_handle<stream_handle_service> stream_handle;
|
||||
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
template <typename Executor>
|
||||
class basic_stream_handle;
|
||||
typedef basic_stream_handle<executor> stream_handle;
|
||||
typedef basic_stream_handle<any_io_executor> stream_handle;
|
||||
|
||||
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
|
||||
|
||||
#if defined(BOOST_ASIO_ENABLE_OLD_SERVICES)
|
||||
class object_handle_service;
|
||||
|
||||
template <typename ObjectHandleService>
|
||||
class basic_object_handle;
|
||||
|
||||
typedef basic_object_handle<object_handle_service> object_handle;
|
||||
#else /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
template <typename Executor>
|
||||
class basic_object_handle;
|
||||
typedef basic_object_handle<executor> object_handle;
|
||||
#endif /* defined(BOOST_ASIO_ENABLE_OLD_SERVICES) */
|
||||
typedef basic_object_handle<any_io_executor> object_handle;
|
||||
|
||||
} //windows
|
||||
} //asio
|
||||
|
||||
@@ -48,6 +48,7 @@ class async_pipe
|
||||
public:
|
||||
typedef ::boost::winapi::HANDLE_ native_handle_type;
|
||||
typedef ::boost::asio::windows::stream_handle handle_type;
|
||||
typedef typename handle_type::executor_type executor_type;
|
||||
|
||||
async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios, make_pipe_name(), true) {}
|
||||
async_pipe(boost::asio::io_context & ios_source, boost::asio::io_context & ios_sink)
|
||||
|
||||
@@ -30,14 +30,17 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
|
||||
{
|
||||
std::string st = exe;
|
||||
|
||||
//put in quotes if it has spaces
|
||||
//put in quotes if it has spaces or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
boost::replace_all(st, "\"", "\\\"");
|
||||
auto it = st.find_first_of(" \"");
|
||||
|
||||
auto it = std::find(st.begin(), st.end(), ' ');
|
||||
|
||||
if (it != st.end())//contains spaces.
|
||||
if(it != st.npos)//contains spaces.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, "\"", "\"\"");
|
||||
|
||||
// surround with quotes
|
||||
st.insert(st.begin(), '"');
|
||||
st += '"';
|
||||
}
|
||||
@@ -45,15 +48,18 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
|
||||
|
||||
for (auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, "\"", "\\\"");
|
||||
|
||||
auto it = std::find(arg.begin(), arg.end(), ' ');//contains space?
|
||||
if (it != arg.end())//ok, contains spaces.
|
||||
if(!arg.empty())
|
||||
{
|
||||
//the first one is put directly onto the output,
|
||||
//because then I don't have to copy the whole string
|
||||
arg.insert(arg.begin(), '"');
|
||||
arg += '"'; //thats the post one.
|
||||
auto it = arg.find_first_of(" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(arg, "\"", "\"\"");
|
||||
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), '"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
@@ -68,30 +74,36 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
|
||||
{
|
||||
std::wstring st = exe;
|
||||
|
||||
//put in quotes if it has spaces
|
||||
//put in quotes if it has spaces or double quotes
|
||||
if(!exe.empty())
|
||||
{
|
||||
boost::replace_all(st, L"\"", L"\\\"");
|
||||
auto it = st.find_first_of(L" \"");
|
||||
|
||||
auto it = std::find(st.begin(), st.end(), L' ');
|
||||
|
||||
if (it != st.end())//contains spaces.
|
||||
if(it != st.npos)//contains spaces or double quotes.
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(st, L"\"", L"\"\"");
|
||||
|
||||
// surround with quotes
|
||||
st.insert(st.begin(), L'"');
|
||||
st += L'"';
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & arg : data)
|
||||
for(auto & arg : data)
|
||||
{
|
||||
boost::replace_all(arg, L"\"", L"\\\"");
|
||||
|
||||
auto it = std::find(arg.begin(), arg.end(), L' ');//contains space?
|
||||
if (it != arg.end())//ok, contains spaces.
|
||||
if(!arg.empty())
|
||||
{
|
||||
//the first one is put directly onto the output,
|
||||
//because then I don't have to copy the whole string
|
||||
arg.insert(arg.begin(), L'"');
|
||||
arg += L'"'; //thats the post one.
|
||||
auto it = arg.find_first_of(L" \"");//contains space or double quotes?
|
||||
if(it != arg.npos)//yes
|
||||
{
|
||||
// double existing quotes
|
||||
boost::replace_all(arg, L"\"", L"\"\"");
|
||||
|
||||
// surround with quotes
|
||||
arg.insert(arg.begin(), L'"');
|
||||
arg += '"';
|
||||
}
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
@@ -147,8 +159,13 @@ struct exe_cmd_init : handler_base_ext
|
||||
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
static std:: string get_shell(char) {return shell(). string(); }
|
||||
static std::wstring get_shell(wchar_t) {return shell().wstring(); }
|
||||
#else
|
||||
static std:: string get_shell(char) {return shell(). string(codecvt()); }
|
||||
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
|
||||
#endif
|
||||
|
||||
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
typedef int pid_t;
|
||||
typedef ::boost::winapi::DWORD_ pid_t;
|
||||
|
||||
struct child_handle
|
||||
{
|
||||
@@ -66,7 +66,7 @@ struct child_handle
|
||||
|
||||
pid_t id() const
|
||||
{
|
||||
return static_cast<int>(proc_info.dwProcessId);
|
||||
return static_cast<pid_t>(proc_info.dwProcessId);
|
||||
}
|
||||
|
||||
typedef ::boost::winapi::HANDLE_ process_handle_t;
|
||||
|
||||
@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
|
||||
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
|
||||
else
|
||||
return std::basic_string<Char>(
|
||||
buf.data(), buf.data()+ size + 1);
|
||||
buf.data(), buf.data()+ size);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return std::basic_string<Char>(buf, buf+size+1);
|
||||
return std::basic_string<Char>(buf, buf+size);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
@@ -232,6 +232,8 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
|
||||
template<typename Char>
|
||||
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
|
||||
{
|
||||
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
|
||||
return string_type(_data.data());
|
||||
|
||||
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
|
||||
return string_type(_data.data()); //null-char is handled by the string.
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include <boost/winapi/handles.hpp>
|
||||
#include <boost/winapi/file_management.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
@@ -39,7 +40,7 @@ struct file_descriptor
|
||||
}
|
||||
|
||||
file_descriptor() = default;
|
||||
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
|
||||
file_descriptor(const boost::process::filesystem::path& p, mode_t mode = read_write)
|
||||
: file_descriptor(p.native(), mode)
|
||||
{
|
||||
}
|
||||
@@ -90,10 +91,19 @@ struct file_descriptor
|
||||
|
||||
}
|
||||
file_descriptor(const file_descriptor & ) = delete;
|
||||
file_descriptor(file_descriptor && ) = default;
|
||||
file_descriptor(file_descriptor &&other)
|
||||
: _handle( boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_) )
|
||||
{
|
||||
}
|
||||
|
||||
file_descriptor& operator=(const file_descriptor & ) = delete;
|
||||
file_descriptor& operator=(file_descriptor && ) = default;
|
||||
file_descriptor& operator=(file_descriptor &&other)
|
||||
{
|
||||
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
|
||||
::boost::winapi::CloseHandle(_handle);
|
||||
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file_descriptor()
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//#define BOOST_USE_WINDOWS_H 1
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
#include <Winternl.h>
|
||||
#include <winternl.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -198,20 +198,20 @@ typedef struct _OBJECT_TYPE_INFORMATION_ {
|
||||
|
||||
|
||||
/*
|
||||
__kernel_entry NTSTATUS NtQuerySystemInformation(
|
||||
NTSTATUS NtQuerySystemInformation(
|
||||
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||
OUT PVOID SystemInformation,
|
||||
IN ULONG SystemInformationLength,
|
||||
OUT PULONG ReturnLength
|
||||
);
|
||||
*/
|
||||
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_system_query_information_p )(
|
||||
typedef ::boost::winapi::NTSTATUS_ (*nt_system_query_information_p )(
|
||||
SYSTEM_INFORMATION_CLASS_,
|
||||
void *,
|
||||
::boost::winapi::ULONG_,
|
||||
::boost::winapi::PULONG_);
|
||||
/*
|
||||
__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
|
||||
NTSYSCALLAPI NTSTATUS NtQueryObject(
|
||||
HANDLE Handle,
|
||||
OBJECT_INFORMATION_CLASS ObjectInformationClass,
|
||||
PVOID ObjectInformation,
|
||||
@@ -220,7 +220,7 @@ __kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
|
||||
);
|
||||
*/
|
||||
|
||||
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_query_object_p )(
|
||||
typedef ::boost::winapi::NTSTATUS_ (*nt_query_object_p )(
|
||||
::boost::winapi::HANDLE_,
|
||||
OBJECT_INFORMATION_CLASS_,
|
||||
void *,
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/process/detail/windows/handle_workaround.hpp>
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <boost/winapi/get_current_process_id.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
@@ -34,12 +35,12 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
|
||||
::boost::winapi::NTSTATUS_ nt_status = STATUS_INFO_LENGTH_MISMATCH_;
|
||||
|
||||
for (int cnt = 0;
|
||||
for (;
|
||||
nt_status == STATUS_INFO_LENGTH_MISMATCH_;
|
||||
nt_status = workaround::nt_system_query_information(
|
||||
workaround::SystemHandleInformation_,
|
||||
info_pointer, buffer.size(),
|
||||
NULL))
|
||||
info_pointer, static_cast<::boost::winapi::ULONG_>(buffer.size()),
|
||||
nullptr))
|
||||
{
|
||||
buffer.resize(buffer.size() * 2);
|
||||
info_pointer = reinterpret_cast<workaround::SYSTEM_HANDLE_INFORMATION_*>(buffer.data());
|
||||
@@ -136,7 +137,7 @@ struct limit_handles_ : handler_base_ext
|
||||
[&](::boost::winapi::HANDLE_ handle)
|
||||
{
|
||||
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
|
||||
DWORD flags = 0u;
|
||||
::boost::winapi::DWORD_ flags = 0u;
|
||||
if (itr != all_handles.end())
|
||||
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
|
||||
else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0)
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/is_running.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/windows/object_handle.hpp>
|
||||
#include <boost/winapi/process.hpp>
|
||||
#include <boost/winapi/handles.hpp>
|
||||
@@ -114,6 +116,15 @@ struct io_context_ref : boost::process::detail::handler_base
|
||||
|
||||
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
|
||||
|
||||
::boost::winapi::DWORD_ code;
|
||||
if(::boost::winapi::GetExitCodeProcess(process_handle, &code)
|
||||
&& code != still_active)
|
||||
{
|
||||
::boost::asio::post(wh.handle->get_executor(), std::move(wh));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
auto handle_p = wh.handle.get();
|
||||
handle_p->async_wait(std::move(wh));
|
||||
}
|
||||
@@ -130,12 +141,13 @@ struct io_context_ref : boost::process::detail::handler_base
|
||||
boost::asio::io_context & ios, void * handle,
|
||||
const std::shared_ptr<std::atomic<int>> &exit_status)
|
||||
: funcs(std::move(funcs)),
|
||||
handle(new boost::asio::windows::object_handle(ios.get_executor(), handle)),
|
||||
handle(new boost::asio::windows::object_handle(
|
||||
asio::prefer(ios.get_executor(), asio::execution::outstanding_work.tracked), handle)),
|
||||
exit_status(exit_status)
|
||||
{
|
||||
|
||||
}
|
||||
void operator()(const boost::system::error_code & ec_in)
|
||||
void operator()(const boost::system::error_code & ec_in = {})
|
||||
{
|
||||
std::error_code ec;
|
||||
if (ec_in)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2106 Klemens D. Morgenstern
|
||||
// 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)
|
||||
@@ -7,6 +7,7 @@
|
||||
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/windows/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <cstdlib>
|
||||
#include <boost/winapi/process.hpp>
|
||||
|
||||
@@ -6,13 +6,20 @@
|
||||
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/asio/execution.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup);
|
||||
|
||||
namespace windows {
|
||||
|
||||
struct on_exit_ : boost::process::detail::windows::async_handler
|
||||
{
|
||||
@@ -23,10 +30,12 @@ struct on_exit_ : boost::process::detail::windows::async_handler
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
|
||||
{
|
||||
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
|
||||
boost::asio::execution::outstanding_work.tracked);
|
||||
auto handler_ = this->handler;
|
||||
return [handler_](int exit_code, const std::error_code & ec)
|
||||
return [v, handler_](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler_(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
@@ -24,9 +23,9 @@
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline boost::filesystem::path search_path(
|
||||
const boost::filesystem::path &filename,
|
||||
const std::vector<boost::filesystem::path> &path)
|
||||
inline boost::process::filesystem::path search_path(
|
||||
const boost::process::filesystem::path &filename,
|
||||
const std::vector<boost::process::filesystem::path> &path)
|
||||
{
|
||||
const ::boost::process::wnative_environment ne{};
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
@@ -36,7 +35,9 @@ inline boost::filesystem::path search_path(
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
|
||||
|
||||
auto extensions_in = itr->to_vector();
|
||||
std::vector<std::wstring> extensions_in;
|
||||
if (itr != ne.cend())
|
||||
extensions_in = itr->to_vector();
|
||||
|
||||
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
|
||||
|
||||
@@ -55,19 +56,23 @@ inline boost::filesystem::path search_path(
|
||||
for (auto & ext : extensions)
|
||||
boost::to_lower(ext);
|
||||
|
||||
for (const boost::filesystem::path & pp_ : path)
|
||||
for (const boost::process::filesystem::path & pp_ : path)
|
||||
{
|
||||
auto p = pp_ / filename;
|
||||
for (boost::filesystem::path ext : extensions)
|
||||
for (boost::process::filesystem::path ext : extensions)
|
||||
{
|
||||
boost::filesystem::path pp = p;
|
||||
pp += ext;
|
||||
boost::process::filesystem::path pp_ext = p;
|
||||
pp_ext += ext;
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
std::error_code ec;
|
||||
#else
|
||||
boost::system::error_code ec;
|
||||
bool file = boost::filesystem::is_regular_file(pp, ec);
|
||||
#endif
|
||||
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
|
||||
if (!ec && file &&
|
||||
::boost::winapi::sh_get_file_info(pp.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
|
||||
{
|
||||
return pp;
|
||||
return pp_ext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,29 +12,29 @@
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
#include <boost/winapi/basic_types.hpp>
|
||||
#include <boost/winapi/get_system_directory.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace windows {
|
||||
|
||||
inline boost::filesystem::path shell_path()
|
||||
inline boost::process::filesystem::path shell_path()
|
||||
{
|
||||
::boost::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
if (!size)
|
||||
throw_last_error("GetSystemDirectory() failed");
|
||||
|
||||
boost::filesystem::path p = sysdir;
|
||||
boost::process::filesystem::path p = sysdir;
|
||||
return p / "cmd.exe";
|
||||
}
|
||||
|
||||
inline boost::filesystem::path shell_path(std::error_code &ec) noexcept
|
||||
inline boost::process::filesystem::path shell_path(std::error_code &ec) noexcept
|
||||
{
|
||||
|
||||
::boost::winapi::WCHAR_ sysdir[260];
|
||||
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
|
||||
boost::filesystem::path p;
|
||||
boost::process::filesystem::path p;
|
||||
if (!size)
|
||||
ec = std::error_code(
|
||||
::boost::winapi::GetLastError(),
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/none.hpp>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/environment.hpp>
|
||||
@@ -44,7 +44,7 @@ struct const_entry
|
||||
bool operator()(char c) const {return c == api::env_seperator<char> ();}
|
||||
} s;
|
||||
boost::split(data, _data, s);
|
||||
return std::move(data);
|
||||
return data;
|
||||
}
|
||||
string_type to_string() const
|
||||
{
|
||||
@@ -263,7 +263,9 @@ public:
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
@@ -275,7 +277,9 @@ public:
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
@@ -288,7 +292,9 @@ public:
|
||||
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
return 1u;
|
||||
p++;
|
||||
}
|
||||
@@ -672,16 +678,16 @@ inline native_environment environment() { return ::boost::process:: native_env
|
||||
///Get the enviroment of the current process.
|
||||
inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
|
||||
///Get the path environment variable of the current process runs.
|
||||
inline std::vector<boost::filesystem::path> path()
|
||||
inline std::vector<boost::process::filesystem::path> path()
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const ::boost::process::wnative_environment ne{};
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
const auto id = L"PATH";
|
||||
static constexpr auto id = L"PATH";
|
||||
#else
|
||||
const ::boost::process::native_environment ne{};
|
||||
typedef typename ::boost::process::native_environment::const_entry_type value_type;
|
||||
const auto id = "PATH";
|
||||
static constexpr auto id = "PATH";
|
||||
#endif
|
||||
|
||||
auto itr = std::find_if(ne.cbegin(), ne.cend(),
|
||||
@@ -693,7 +699,7 @@ inline std::vector<boost::filesystem::path> path()
|
||||
|
||||
auto vec = itr->to_vector();
|
||||
|
||||
std::vector<boost::filesystem::path> val;
|
||||
std::vector<boost::process::filesystem::path> val;
|
||||
val.resize(vec.size());
|
||||
|
||||
std::copy(vec.begin(), vec.end(), val.begin());
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace detail {
|
||||
|
||||
struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr throw_on_error_() {};
|
||||
constexpr throw_on_error_() = default;
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
@@ -72,7 +72,7 @@ struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
|
||||
struct ignore_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr ignore_error_() {};
|
||||
constexpr ignore_error_() = default;
|
||||
};
|
||||
|
||||
struct set_on_error : ::boost::process::detail::api::handler_base_ext
|
||||
@@ -81,7 +81,7 @@ struct set_on_error : ::boost::process::detail::api::handler_base_ext
|
||||
explicit set_on_error(std::error_code &ec) : ec_(ec) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
void on_error(Executor&, const std::error_code & ec) const noexcept
|
||||
{
|
||||
ec_ = ec;
|
||||
}
|
||||
@@ -92,7 +92,7 @@ private:
|
||||
|
||||
struct error_
|
||||
{
|
||||
constexpr error_() {}
|
||||
constexpr error_() = default;
|
||||
set_on_error operator()(std::error_code &ec) const {return set_on_error(ec);}
|
||||
set_on_error operator= (std::error_code &ec) const {return set_on_error(ec);}
|
||||
|
||||
|
||||
@@ -36,15 +36,15 @@ namespace detail {
|
||||
struct exe_
|
||||
{
|
||||
template<typename = void>
|
||||
inline exe_setter_<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & pth) const
|
||||
inline exe_setter_<typename boost::process::filesystem::path::value_type> operator()(const boost::process::filesystem::path & pth) const
|
||||
{
|
||||
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
|
||||
return exe_setter_<typename boost::process::filesystem::path::value_type>(pth.native());
|
||||
}
|
||||
|
||||
template<typename = void>
|
||||
inline exe_setter_<typename boost::filesystem::path::value_type> operator=(const boost::filesystem::path & pth) const
|
||||
inline exe_setter_<typename boost::process::filesystem::path::value_type> operator=(const boost::process::filesystem::path & pth) const
|
||||
{
|
||||
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
|
||||
return exe_setter_<typename boost::process::filesystem::path::value_type>(pth.native());
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ The overload form applies when to the first, when several strings are passed to
|
||||
function.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
|
||||
a `std::basic_string` with `char` or `wchar_t` or a `boost::process::filesystem::path`.
|
||||
|
||||
\code{.cpp}
|
||||
exe="value";
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <memory>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
|
||||
28
include/boost/process/filesystem.hpp
Normal file
28
include/boost/process/filesystem.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_PROCESS_FILESYSTEM_HPP
|
||||
#define BOOST_PROCESS_FILESYSTEM_HPP
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BOOST_PROCESS_FILESYSTEM_HPP
|
||||
@@ -122,9 +122,11 @@ public:
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
@@ -132,6 +134,7 @@ public:
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
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 boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
@@ -140,17 +143,19 @@ public:
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
|
||||
}
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
|
||||
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
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
|
||||
@@ -60,9 +60,9 @@ namespace boost {
|
||||
The library allows full redirection of streams to files as shown below.
|
||||
|
||||
\code{.cpp}
|
||||
boost::filesystem::path log = "my_log_file.txt";
|
||||
boost::filesystem::path input = "input.txt";
|
||||
boost::filesystem::path output = "output.txt";
|
||||
boost::process::filesystem::path log = "my_log_file.txt";
|
||||
boost::process::filesystem::path input = "input.txt";
|
||||
boost::process::filesystem::path output = "output.txt";
|
||||
system("my_prog", std_out>output, std_in<input, std_err>log);
|
||||
\endcode
|
||||
|
||||
@@ -136,13 +136,13 @@ template<typename T> using is_mutable_buffer =
|
||||
>;
|
||||
|
||||
|
||||
struct null_t {constexpr null_t() {}};
|
||||
struct null_t {constexpr null_t() = default;};
|
||||
struct close_t;
|
||||
|
||||
template<class>
|
||||
struct std_in_
|
||||
{
|
||||
constexpr std_in_() {}
|
||||
constexpr std_in_() = default;
|
||||
|
||||
api::close_in close() const {return api::close_in(); }
|
||||
api::close_in operator=(const close_t &) const {return api::close_in();}
|
||||
@@ -152,13 +152,13 @@ struct std_in_
|
||||
api::null_in operator=(const null_t &) const {return api::null_in();}
|
||||
api::null_in operator<(const null_t &) const {return api::null_in();}
|
||||
|
||||
api::file_in operator=(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator=(const boost::process::filesystem::path &p) const {return p;}
|
||||
api::file_in operator=(const std::string & p) const {return p;}
|
||||
api::file_in operator=(const std::wstring &p) const {return p;}
|
||||
api::file_in operator=(const char * p) const {return p;}
|
||||
api::file_in operator=(const wchar_t * p) const {return p;}
|
||||
|
||||
api::file_in operator<(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator<(const boost::process::filesystem::path &p) const {return p;}
|
||||
api::file_in operator<(const std::string &p) const {return p;}
|
||||
api::file_in operator<(const std::wstring &p) const {return p;}
|
||||
api::file_in operator<(const char*p) const {return p;}
|
||||
@@ -199,7 +199,7 @@ struct std_in_
|
||||
template<int p1, int p2 = -1>
|
||||
struct std_out_
|
||||
{
|
||||
constexpr std_out_() {}
|
||||
constexpr std_out_() = default;
|
||||
|
||||
api::close_out<p1,p2> close() const {return api::close_out<p1,p2>(); }
|
||||
api::close_out<p1,p2> operator=(const close_t &) const {return api::close_out<p1,p2>();}
|
||||
@@ -209,13 +209,13 @@ struct std_out_
|
||||
api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
|
||||
api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const boost::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const boost::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
@@ -260,7 +260,7 @@ struct std_out_
|
||||
|
||||
struct close_t
|
||||
{
|
||||
constexpr close_t() {}
|
||||
constexpr close_t() = default;
|
||||
template<int T, int U>
|
||||
api::close_out<T,U> operator()(std_out_<T,U>) {return api::close_out<T,U>();}
|
||||
};
|
||||
@@ -282,7 +282,7 @@ This property allows to set the input stream for the child process.
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `boost::process::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
@@ -424,7 +424,7 @@ This property allows to set the output stream for the child process.
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `boost::process::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace detail
|
||||
class codecvt_category_t : public std::error_category
|
||||
{
|
||||
public:
|
||||
codecvt_category_t(){}
|
||||
codecvt_category_t() = default;
|
||||
const char* name() const noexcept override {return "codecvt";}
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
@@ -76,9 +76,8 @@ inline std::locale default_locale()
|
||||
std::locale global_loc = std::locale();
|
||||
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
|
||||
# else // Other POSIX
|
||||
// ISO C calls std::locale("") "the locale-specific native environment", and this
|
||||
// locale is the default for many POSIX-based operating systems such as Linux.
|
||||
return std::locale("");
|
||||
// Return a default locale object.
|
||||
return std::locale();
|
||||
# endif
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
///Destructor -> writes the frest of the data
|
||||
~basic_pipebuf()
|
||||
{
|
||||
if (is_open())
|
||||
overflow(Traits::eof());
|
||||
if (basic_pipebuf::is_open())
|
||||
basic_pipebuf::overflow(Traits::eof());
|
||||
}
|
||||
|
||||
///Move construct from a pipe.
|
||||
@@ -167,10 +167,12 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
if (this->pptr() == this->epptr())
|
||||
{
|
||||
bool wr = this->_write_impl();
|
||||
*this->pptr() = ch;
|
||||
this->pbump(1);
|
||||
if (wr)
|
||||
{
|
||||
*this->pptr() = ch;
|
||||
this->pbump(1);
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -277,7 +279,7 @@ private:
|
||||
else if (wrt == 0) //broken pipe
|
||||
return false;
|
||||
|
||||
this->pbump(-wrt);
|
||||
this->pbump(static_cast<int>(-wrt));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -340,8 +342,9 @@ public:
|
||||
basic_ipstream& operator=(basic_ipstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
///Move assignment of a pipe.
|
||||
basic_ipstream& operator=(pipe_type && p)
|
||||
@@ -366,7 +369,7 @@ public:
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
///Check if the pipe is open
|
||||
bool is_open() const {return _buf->is_open();}
|
||||
bool is_open() const {return _buf.is_open();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
@@ -448,8 +451,9 @@ public:
|
||||
basic_opstream& operator=(basic_opstream && lhs)
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
|
||||
///Move assignment of a pipe.
|
||||
@@ -556,8 +560,9 @@ public:
|
||||
basic_pstream& operator=(basic_pstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs);
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
///Move assignment of a pipe.
|
||||
basic_pstream& operator=(pipe_type && p)
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace boost { namespace process {
|
||||
* \returns the absolute path to the executable filename or an
|
||||
* empty string if filename isn't found
|
||||
*/
|
||||
inline boost::filesystem::path search_path(const boost::filesystem::path &filename,
|
||||
const std::vector<boost::filesystem::path> path = ::boost::this_process::path())
|
||||
inline boost::process::filesystem::path search_path(const boost::process::filesystem::path &filename,
|
||||
const std::vector<boost::process::filesystem::path> path = ::boost::this_process::path())
|
||||
{
|
||||
return ::boost::process::detail::api::search_path(filename, path);
|
||||
}
|
||||
|
||||
@@ -44,18 +44,18 @@ struct shell_
|
||||
{
|
||||
constexpr shell_() {}
|
||||
|
||||
boost::filesystem::path operator()() const
|
||||
boost::process::filesystem::path operator()() const
|
||||
{
|
||||
return boost::process::detail::api::shell_path();
|
||||
}
|
||||
boost::filesystem::path operator()(std::error_code & ec) const noexcept
|
||||
boost::process::filesystem::path operator()(std::error_code & ec) const noexcept
|
||||
{
|
||||
return boost::process::detail::api::shell_path(ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_wchar_t<shell_> : is_wchar_t<boost::filesystem::path>
|
||||
struct is_wchar_t<shell_> : is_wchar_t<boost::process::filesystem::path>
|
||||
{
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/filesystem.hpp>
|
||||
|
||||
/** \file boost/process/start_dir.hpp
|
||||
*
|
||||
@@ -53,8 +53,8 @@ struct start_dir_
|
||||
api::start_dir_init<Char> operator()(std::basic_string<Char> && s) const {return {std::move(s)}; }
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator()(const Char* s) const {return {s}; }
|
||||
api::start_dir_init<typename boost::filesystem::path::value_type>
|
||||
operator()(const boost::filesystem::path & st) const {return {st.native()}; }
|
||||
api::start_dir_init<typename boost::process::filesystem::path::value_type>
|
||||
operator()(const boost::process::filesystem::path & st) const {return {st.native()}; }
|
||||
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; }
|
||||
@@ -62,8 +62,8 @@ struct start_dir_
|
||||
api::start_dir_init<Char> operator= (std::basic_string<Char> && s) const {return {std::move(s)}; }
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator= (const Char* s) const {return {s}; }
|
||||
api::start_dir_init<typename boost::filesystem::path::value_type>
|
||||
operator= (const boost::filesystem::path & st) const {return {st.native()}; }
|
||||
api::start_dir_init<typename boost::process::filesystem::path::value_type>
|
||||
operator= (const boost::process::filesystem::path & st) const {return {st.native()}; }
|
||||
|
||||
};
|
||||
|
||||
@@ -100,7 +100,7 @@ start_dir=path
|
||||
start_dir(path)
|
||||
\endcode
|
||||
|
||||
It can be used with `std::string`, `std::wstring` and `boost::filesystem::path`.
|
||||
It can be used with `std::string`, `std::wstring` and `boost::process::filesystem::path`.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
19
include/boost/process/v2.hpp
Normal file
19
include/boost/process/v2.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2022 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_V2_HPP
|
||||
#define BOOST_PROCESS_V2_HPP
|
||||
|
||||
#include <boost/process/v2/error.hpp>
|
||||
#include <boost/process/v2/environment.hpp>
|
||||
#include <boost/process/v2/execute.hpp>
|
||||
#include <boost/process/v2/exit_code.hpp>
|
||||
#include <boost/process/v2/pid.hpp>
|
||||
#include <boost/process/v2/popen.hpp>
|
||||
#include <boost/process/v2/process_handle.hpp>
|
||||
#include <boost/process/v2/process.hpp>
|
||||
#include <boost/process/v2/start_dir.hpp>
|
||||
#include <boost/process/v2/stdio.hpp>
|
||||
|
||||
#endif //BOOST_PROCESS_V2_HPP
|
||||
240
include/boost/process/v2/bind_launcher.hpp
Normal file
240
include/boost/process/v2/bind_launcher.hpp
Normal file
@@ -0,0 +1,240 @@
|
||||
//
|
||||
// boost/process/v2/bind_launcher.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_BIND_LAUNCHER_HPP
|
||||
#define BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/default_launcher.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<std::size_t ... Idx>
|
||||
struct index_sequence { };
|
||||
|
||||
template<std::size_t Size, typename T>
|
||||
struct make_index_sequence_impl;
|
||||
|
||||
template<std::size_t Size, std::size_t ... Idx>
|
||||
struct make_index_sequence_impl<Size, index_sequence<Idx...>>
|
||||
{
|
||||
constexpr make_index_sequence_impl() {}
|
||||
using type = typename make_index_sequence_impl<Size - 1u, index_sequence<Size - 1u, Idx...>>::type;
|
||||
};
|
||||
|
||||
template<std::size_t ... Idx>
|
||||
struct make_index_sequence_impl<0u, index_sequence<Idx...>>
|
||||
{
|
||||
constexpr make_index_sequence_impl() {}
|
||||
using type = index_sequence<Idx...>;
|
||||
};
|
||||
|
||||
|
||||
template<std::size_t Cnt>
|
||||
struct make_index_sequence
|
||||
{
|
||||
using type = typename make_index_sequence_impl<Cnt, index_sequence<>>::type;
|
||||
};
|
||||
|
||||
template<std::size_t Cnt>
|
||||
using make_index_sequence_t = typename make_index_sequence<Cnt>::type;
|
||||
|
||||
}
|
||||
|
||||
/** @brief Utility class to bind initializers to a launcher
|
||||
* @tparam Launcher The inner launcher to be used
|
||||
* @tparam ...Init The initializers to be prepended.
|
||||
*
|
||||
* This can be used when multiple processes shared some settings,
|
||||
* e.g.
|
||||
*
|
||||
*/
|
||||
template<typename Launcher, typename ... Init>
|
||||
struct bound_launcher
|
||||
{
|
||||
template<typename Launcher_, typename ... Init_>
|
||||
bound_launcher(Launcher_ && l, Init_ && ... init) :
|
||||
launcher_(std::forward<Launcher_>(l)), init_(std::forward<Init_>(init)...)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto operator()(ExecutionContext & context,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
context,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
|
||||
template<typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto operator()(ExecutionContext & context,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
context, ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<typename Executor, typename Args, typename ... Inits>
|
||||
auto operator()(Executor exec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
std::move(exec),
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<typename Executor, typename Args, typename ... Inits>
|
||||
auto operator()(Executor exec,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
|
||||
std::move(exec), ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
private:
|
||||
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
ExecutionContext & context,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return launcher_(context,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
|
||||
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
ExecutionContext & context,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<std::is_convertible<
|
||||
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
|
||||
{
|
||||
return launcher_(context, ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
Executor exec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return launcher_(std::move(exec),
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
|
||||
auto invoke(detail::index_sequence<Idx...>,
|
||||
Executor exec,
|
||||
error_code & ec,
|
||||
const typename std::enable_if<
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
|
||||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
|
||||
filesystem::path >::type & executable,
|
||||
Args && args,
|
||||
Inits && ... inits ) -> basic_process<Executor>
|
||||
{
|
||||
return launcher_(std::move(exec), ec,
|
||||
executable,
|
||||
std::forward<Args>(args),
|
||||
std::get<Idx>(init_)...,
|
||||
std::forward<Inits>(inits)...);
|
||||
}
|
||||
|
||||
Launcher launcher_;
|
||||
std::tuple<Init...> init_;
|
||||
};
|
||||
|
||||
|
||||
template<typename Launcher, typename ... Init>
|
||||
auto bind_launcher(Launcher && launcher, Init && ... init)
|
||||
-> bound_launcher<typename std::decay<Launcher>::type,
|
||||
typename std::decay<Init>::type...>
|
||||
{
|
||||
return bound_launcher<typename std::decay<Launcher>::type,
|
||||
typename std::decay<Init>::type...>(
|
||||
std::forward<Launcher>(launcher),
|
||||
std::forward<Init>(init)...);
|
||||
}
|
||||
|
||||
/// @brief @overload bind_launcher(Launcher && launcher, Init && init)
|
||||
/// @tparam ...Init The initializer types to bind to the default_launcher.
|
||||
/// @param ...init The initializers types to bind to the default_launcher.
|
||||
/// @return The new default_launcher.
|
||||
template<typename ... Init>
|
||||
auto bind_default_launcher(Init && ... init)
|
||||
-> bound_launcher<default_process_launcher,
|
||||
typename std::decay<Init>::type...>
|
||||
{
|
||||
return bound_launcher<default_process_launcher,
|
||||
typename std::decay<Init>::type...>(
|
||||
default_process_launcher(),
|
||||
std::forward<Init>(init)...);
|
||||
}
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif // BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
|
||||
232
include/boost/process/v2/cstring_ref.hpp
Normal file
232
include/boost/process/v2/cstring_ref.hpp
Normal file
@@ -0,0 +1,232 @@
|
||||
// Copyright (c) 2022 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_V2_CSTRING_REF_HPP
|
||||
#define BOOST_PROCESS_V2_CSTRING_REF_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
#include <string_view>
|
||||
#else
|
||||
#include <boost/utility/string_view.hpp>
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_CONSTEXPR static const char* null_char_(char) {return "";}
|
||||
BOOST_CONSTEXPR static const wchar_t* null_char_(wchar_t) {return L"";}
|
||||
BOOST_CONSTEXPR static const char16_t* null_char_(char16_t) {return u"";}
|
||||
BOOST_CONSTEXPR static const char32_t* null_char_(char32_t) {return U"";}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HAS_CHAR8_T)
|
||||
BOOST_CONSTEXPR static const char8_t* null_char_(char8_t) {return u8"";}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
using std::basic_string_view;
|
||||
using std:: string_view;
|
||||
using std:: wstring_view;
|
||||
#else
|
||||
using boost::basic_string_view;
|
||||
using boost:: string_view;
|
||||
using boost:: wstring_view;
|
||||
#endif
|
||||
|
||||
|
||||
/// Small wrapper for a null-terminated string that can be directly passed to C APIS
|
||||
/** This ref can only be modified by moving the front pointer. It does not store the
|
||||
* size, but can detect values that can directly be passed to system APIs.
|
||||
*
|
||||
* It can be constructed from a `char*` pointer or any class that has a `c_str()`
|
||||
* member function, e.g. std::string or boost::static_string.
|
||||
*
|
||||
*/
|
||||
template<typename CharT, typename Traits = std::char_traits<CharT>>
|
||||
struct basic_cstring_ref
|
||||
{
|
||||
using value_type = CharT;
|
||||
using traits_type = Traits;
|
||||
|
||||
BOOST_CONSTEXPR basic_cstring_ref() noexcept : view_(detail::null_char_(value_type{})) {}
|
||||
BOOST_CONSTEXPR basic_cstring_ref(std::nullptr_t) = delete;
|
||||
|
||||
BOOST_CONSTEXPR basic_cstring_ref( const value_type* s ) : view_(s) {}
|
||||
|
||||
template<typename Source,
|
||||
typename =
|
||||
typename std::enable_if<
|
||||
std::is_same<const value_type,
|
||||
typename std::remove_pointer<decltype(std::declval<Source>().c_str())>::type
|
||||
>::value>::type>
|
||||
BOOST_CONSTEXPR basic_cstring_ref(Source && src) : view_(src.c_str()) {}
|
||||
|
||||
BOOST_CONSTEXPR typename basic_string_view<value_type, Traits>::const_pointer c_str() const BOOST_NOEXCEPT
|
||||
{
|
||||
return this->data();
|
||||
}
|
||||
|
||||
using string_view_type = basic_string_view<value_type, Traits>;
|
||||
constexpr operator string_view_type() const {return view_;}
|
||||
|
||||
using pointer = CharT *;
|
||||
using const_pointer = const CharT *;
|
||||
using reference = CharT &;
|
||||
using const_reference = const CharT &;
|
||||
using const_iterator = const_pointer;
|
||||
using iterator = const_iterator;
|
||||
using const_reverse_iterator = typename std::reverse_iterator<const_iterator>;
|
||||
using reverse_iterator = typename std::reverse_iterator<iterator>;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
static BOOST_CONSTEXPR size_type npos = -1;
|
||||
|
||||
BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT {return view_;};
|
||||
BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT {return view_ + length();};
|
||||
BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT {return view_;};
|
||||
BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT {return view_ + length();};
|
||||
BOOST_CONSTEXPR const_reverse_iterator rbegin() const BOOST_NOEXCEPT {return reverse_iterator(view_ + length());};
|
||||
BOOST_CONSTEXPR const_reverse_iterator rend() const BOOST_NOEXCEPT {return reverse_iterator(view_);};
|
||||
BOOST_CONSTEXPR const_reverse_iterator crbegin() const BOOST_NOEXCEPT {return reverse_iterator(view_ + length());};
|
||||
BOOST_CONSTEXPR const_reverse_iterator crend() const BOOST_NOEXCEPT {return reverse_iterator(view_);};
|
||||
|
||||
BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT {return length(); }
|
||||
BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT {return traits_type::length(view_); }
|
||||
BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT {return (std::numeric_limits<std::size_t>::max)() / sizeof(CharT); }
|
||||
BOOST_ATTRIBUTE_NODISCARD BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT {return *view_ == *detail::null_char_(CharT{}); }
|
||||
|
||||
BOOST_CONSTEXPR const_reference operator[](size_type pos) const {return view_[pos] ;}
|
||||
BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const
|
||||
{
|
||||
if (pos >= size())
|
||||
throw_exception(std::out_of_range("cstring-view out of range"));
|
||||
return view_[pos];
|
||||
}
|
||||
BOOST_CONSTEXPR const_reference front() const {return *view_;}
|
||||
BOOST_CONSTEXPR const_reference back() const {return view_[length() - 1];}
|
||||
BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT {return view_;}
|
||||
BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n) {view_ = view_ + n;}
|
||||
void swap(basic_cstring_ref& s) BOOST_NOEXCEPT {std::swap(view_, s.view_);}
|
||||
|
||||
size_type copy(value_type* s, size_type n, size_type pos = 0) const
|
||||
{
|
||||
return traits_type::copy(s, view_ + pos, n) - view_;
|
||||
}
|
||||
BOOST_CONSTEXPR basic_cstring_ref substr(size_type pos = 0) const
|
||||
{
|
||||
return basic_cstring_ref(view_ + pos);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR string_view_type substr(size_type pos, size_type length) const
|
||||
{
|
||||
return string_view_type(view_).substr(pos, length);
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR int compare(basic_cstring_ref x) const BOOST_NOEXCEPT
|
||||
{
|
||||
auto idx = 0u;
|
||||
for (; view_[idx] != null_char_()[0] && x[idx] != null_char_()[0]; idx++)
|
||||
if (!traits_type::eq(view_[idx], x[idx]))
|
||||
return traits_type::lt(view_[idx], x[idx]) ? -1 : 1;
|
||||
|
||||
return traits_type::to_int_type(view_[idx]) -
|
||||
traits_type::to_int_type(x[idx]); // will compare to null char of either.
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR bool starts_with(string_view_type x) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (x.empty())
|
||||
return true;
|
||||
|
||||
auto idx = 0u;
|
||||
for (; view_[idx] != null_char_()[0] && idx < x.size(); idx++)
|
||||
if (!traits_type::eq(view_[idx], x[idx]))
|
||||
return false;
|
||||
|
||||
return idx == x.size() || view_[idx] != null_char_()[0];
|
||||
}
|
||||
BOOST_CONSTEXPR bool starts_with(value_type x) const BOOST_NOEXCEPT
|
||||
{
|
||||
return traits_type::eq(view_[0], x);
|
||||
}
|
||||
|
||||
BOOST_CXX14_CONSTEXPR size_type find( CharT ch, size_type pos = 0 ) const BOOST_NOEXCEPT
|
||||
{
|
||||
for (auto p = view_ + pos; *p != *null_char_(); p++)
|
||||
if (traits_type::eq(*p, ch))
|
||||
return p - view_;
|
||||
return npos;
|
||||
}
|
||||
|
||||
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator==(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t idx = 0u;
|
||||
for (idx = 0u; x[idx] != null_char_()[0] && y[idx] != null_char_()[0]; idx++)
|
||||
if (!traits_type::eq(x[idx], y[idx]))
|
||||
return false;
|
||||
return x[idx] == y[idx];
|
||||
}
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator!=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT
|
||||
{
|
||||
std::size_t idx = 0u;
|
||||
for (idx = 0u; x[idx] != null_char_()[0] &&
|
||||
y[idx] != null_char_()[0]; idx++)
|
||||
if (!traits_type::eq(x[idx], y[idx]))
|
||||
return true;
|
||||
return x[idx] != y[idx];
|
||||
}
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator< (basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) < 0;}
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator> (basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) > 0;}
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator<=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) <= 0;}
|
||||
friend BOOST_CXX14_CONSTEXPR bool operator>=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) >= 0;}
|
||||
|
||||
// modifiers
|
||||
void clear() BOOST_NOEXCEPT { view_ = null_char_(); } // Boost extension
|
||||
|
||||
std::basic_string<value_type, traits_type> to_string() const {
|
||||
return std::basic_string<CharT, Traits>(begin(), end());
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
std::basic_string<value_type, traits_type, Allocator> to_string(const Allocator& a) const {
|
||||
return std::basic_string<value_type, traits_type, Allocator>(begin(), end(), a);
|
||||
}
|
||||
|
||||
private:
|
||||
BOOST_CONSTEXPR static const_pointer null_char_() {return detail::null_char_(CharT{});}
|
||||
const_pointer view_;
|
||||
};
|
||||
|
||||
template<class charT, class traits>
|
||||
inline std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os,
|
||||
const basic_cstring_ref<charT,traits>& str)
|
||||
{
|
||||
return os << static_cast<basic_string_view<charT, traits>>(str);
|
||||
}
|
||||
|
||||
template <class charT, class traits>
|
||||
std::size_t hash_value(basic_string_view<charT, traits> s) {
|
||||
return boost::hash_range(s.begin(), s.end());
|
||||
}
|
||||
|
||||
using cstring_ref = basic_cstring_ref<char>;
|
||||
using wcstring_ref = basic_cstring_ref<wchar_t>;
|
||||
using u16cstring_ref = basic_cstring_ref<char16_t>;
|
||||
using u32cstring_ref = basic_cstring_ref<char32_t>;
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HAS_CHAR8_T)
|
||||
using u8cstring_ref = basic_cstring_ref<char8_t>;
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_CSTRING_REF_HPP
|
||||
66
include/boost/process/v2/default_launcher.hpp
Normal file
66
include/boost/process/v2/default_launcher.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// boost/process/v2/default_launcher.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_DEFAULT_LAUNCHER_HPP
|
||||
#define BOOST_PROCESS_V2_DEFAULT_LAUNCHER_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <boost/process/v2/windows/default_launcher.hpp>
|
||||
#else
|
||||
#if defined(BOOST_PROCESS_V2_PDFORK)
|
||||
#include <boost/process/v2/posix/pdfork_launcher.hpp>
|
||||
#else
|
||||
#include <boost/process/v2/posix/default_launcher.hpp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(GENERATING_DOCUMENTATION)
|
||||
|
||||
/// The default launcher for processes.
|
||||
/** This launcher will be used by process if a
|
||||
* process is launched through the constructor:
|
||||
*
|
||||
* @code {.cpp}
|
||||
* process proc("test", {});
|
||||
* // equivalent to
|
||||
* process prod = default_launcher()("test", {});
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
typedef implementation_defined default_process_launcher;
|
||||
|
||||
#else
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
typedef windows::default_launcher default_process_launcher;
|
||||
#else
|
||||
#if defined(BOOST_PROCESS_V2_PDFORK)
|
||||
typedef posix::pdfork_launcher default_process_launcher;
|
||||
#else
|
||||
typedef posix::default_launcher default_process_launcher;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
#include <boost/process/v2/impl/default_launcher.ipp>
|
||||
#endif
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DEFAULT_LAUNCHER_HPP
|
||||
180
include/boost/process/v2/detail/config.hpp
Normal file
180
include/boost/process/v2/detail/config.hpp
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright (c) 2022 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_V2_DETAIL_CONFIG_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_STANDALONE)
|
||||
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE asio
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
|
||||
|
||||
#include <asio/detail/config.hpp>
|
||||
#include <system_error>
|
||||
#include <filesystem>
|
||||
#include <string_view>
|
||||
#include <iomanip>
|
||||
#include <optional>
|
||||
|
||||
#if defined(ASIO_WINDOWS)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
|
||||
// Windows: suppress definition of "min" and "max" macros.
|
||||
#if !defined(NOMINMAX)
|
||||
# define NOMINMAX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ASIO_HAS_UNISTD_H)
|
||||
#define BOOST_PROCESS_V2_POSIX 1
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace process_v2 {
|
||||
#define BOOST_PROCESS_V2_END_NAMESPACE }
|
||||
#define BOOST_PROCESS_V2_NAMESPACE process_v2
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
|
||||
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
|
||||
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
|
||||
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/io/quoted.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_category.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#define BOOST_PROCESS_V2_WINDOWS 1
|
||||
|
||||
// Windows: suppress definition of "min" and "max" macros.
|
||||
#if !defined(NOMINMAX)
|
||||
# define NOMINMAX 1
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#define BOOST_PROCESS_V2_POSIX 1
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_PROCESS_V2_WINDOWS) && !defined(BOOST_POSIX_API)
|
||||
#error Unsupported operating system
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_USE_STD_FS)
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
|
||||
#define BOOST_PROCESS_V2_END_NAMESPACE } } }
|
||||
#define BOOST_PROCESS_V2_NAMESPACE boost::process::v2
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
#if defined(BOOST_PROCESS_STANDALONE)
|
||||
|
||||
using std::error_code ;
|
||||
using std::error_category ;
|
||||
using std::system_category ;
|
||||
using std::system_error ;
|
||||
namespace filesystem = std::filesystem;
|
||||
using std::quoted;
|
||||
using std::optional;
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
|
||||
|
||||
|
||||
#else
|
||||
|
||||
using boost::system::error_code ;
|
||||
using boost::system::error_category ;
|
||||
using boost::system::system_category ;
|
||||
using boost::system::system_error ;
|
||||
using boost::io::quoted;
|
||||
using boost::optional;
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(__VA_ARGS__, &loc##__LINE__); \
|
||||
}
|
||||
|
||||
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
|
||||
{ \
|
||||
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
|
||||
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#ifndef BOOST_PROCESS_V2_HEADER_ONLY
|
||||
# ifndef BOOST_PROCESS_V2_SEPARATE_COMPILATION
|
||||
# define BOOST_PROCESS_V2_HEADER_ONLY 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_V2_DOXYGEN
|
||||
# define BOOST_PROCESS_V2_DECL
|
||||
#elif defined(BOOST_PROCESS_V2_HEADER_ONLY)
|
||||
# define BOOST_PROCESS_V2_DECL inline
|
||||
#else
|
||||
# define BOOST_PROCESS_V2_DECL
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_POSIX)
|
||||
|
||||
#if defined(__linux__) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN)
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#if defined(SYS_pidfd_open)
|
||||
#define BOOST_PROCESS_V2_PIDFD_OPEN 1
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
|
||||
#define BOOST_PROCESS_V2_PDFORK 1
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
#else
|
||||
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
|
||||
#endif
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
|
||||
80
include/boost/process/v2/detail/environment_posix.hpp
Normal file
80
include/boost/process/v2/detail/environment_posix.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// process/environment/detail/environment_posix.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_DETAIL_ENVIRONMENT_POSIX_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_POSIX_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
|
||||
extern "C" { extern char **environ; }
|
||||
#endif
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
|
||||
using char_type = char;
|
||||
|
||||
template<typename Char>
|
||||
using key_char_traits = std::char_traits<Char>;
|
||||
|
||||
template<typename Char>
|
||||
using value_char_traits = std::char_traits<Char>;
|
||||
|
||||
|
||||
constexpr char_type equality_sign = '=';
|
||||
constexpr char_type delimiter = ':';
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
basic_cstring_ref<char_type, value_char_traits<char>>
|
||||
get(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec);
|
||||
}
|
||||
|
||||
|
||||
using native_handle_type = const char * const *;
|
||||
using native_iterator = native_handle_type;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
|
||||
struct native_handle_deleter
|
||||
{
|
||||
void operator()(native_handle_type) const {}
|
||||
};
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_iterator next(native_handle_type nh);
|
||||
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
|
||||
inline const char_type * dereference(native_iterator iterator) {return *iterator;}
|
||||
|
||||
BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_code & ec);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif
|
||||
212
include/boost/process/v2/detail/environment_win.hpp
Normal file
212
include/boost/process/v2/detail/environment_win.hpp
Normal file
@@ -0,0 +1,212 @@
|
||||
//
|
||||
// process/environment/detail/environment_win.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#include <cwctype>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
|
||||
using char_type = wchar_t;
|
||||
|
||||
template<typename Char>
|
||||
struct key_char_traits
|
||||
{
|
||||
typedef Char char_type;
|
||||
typedef typename std::char_traits<char_type>::int_type int_type;
|
||||
typedef typename std::char_traits<char_type>::off_type off_type;
|
||||
typedef typename std::char_traits<char_type>::pos_type pos_type;
|
||||
typedef typename std::char_traits<char_type>::state_type state_type;
|
||||
|
||||
BOOST_CONSTEXPR static char to_lower(char c) {return std::tolower(to_int_type(c));}
|
||||
BOOST_CONSTEXPR static wchar_t to_lower(wchar_t c) {return std::towlower(to_int_type(c));}
|
||||
|
||||
BOOST_CONSTEXPR static int_type to_lower(int_type i, char ) {return std::tolower(i);}
|
||||
BOOST_CONSTEXPR static int_type to_lower(int_type i, wchar_t) {return std::towlower(i);}
|
||||
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
void assign(char_type& c1, const char_type& c2) BOOST_NOEXCEPT
|
||||
{
|
||||
c1 = c2;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool eq(char_type c1, char_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1) == to_lower(c2);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool lt(char_type c1, char_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1) < to_lower(c2);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int compare(const char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
auto itrs = std::mismatch(s1, s1 + n, s2, &eq);
|
||||
if (itrs.first == (s1 + n))
|
||||
return 0;
|
||||
auto c1 = to_lower(*itrs.first);
|
||||
auto c2 = to_lower(*itrs.second);
|
||||
|
||||
return (c1 < c2 ) ? -1 : 1;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static size_t length(const char* s) BOOST_NOEXCEPT { return std::strlen(s); }
|
||||
BOOST_CONSTEXPR static size_t length(const wchar_t* s) BOOST_NOEXCEPT { return std::wcslen(s); }
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
const char_type* find(const char_type* s, size_t n, const char_type& a) BOOST_NOEXCEPT
|
||||
{
|
||||
const char_type u = to_lower(a);
|
||||
return std::find_if(s, s + n, [u](char_type c){return to_lower(c) == u;});
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type* move(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
if (s1 < s2)
|
||||
return std::move(s2, s2 + n, s1);
|
||||
else
|
||||
return std::move_backward(s2, s2 + n, s1);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type* copy(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
|
||||
{
|
||||
return std::copy(s2, s2 + n, s1);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type* assign(char_type* s, size_t n, char_type a) BOOST_NOEXCEPT
|
||||
{
|
||||
std::fill(s, s + n, a);
|
||||
return s +n;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type not_eof(int_type c) BOOST_NOEXCEPT
|
||||
{
|
||||
return eq_int_type(c, eof()) ? ~eof() : c;
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
char_type to_char_type(int_type c) BOOST_NOEXCEPT
|
||||
{
|
||||
return char_type(c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type to_int_type(char c) BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type((unsigned char)c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
int_type to_int_type(wchar_t c) BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type((wchar_t)c);
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static
|
||||
bool eq_int_type(int_type c1, int_type c2) BOOST_NOEXCEPT
|
||||
{
|
||||
return to_lower(c1, char_type()) == to_lower(c2, char_type());
|
||||
}
|
||||
|
||||
BOOST_CONSTEXPR static inline int_type eof() BOOST_NOEXCEPT
|
||||
{
|
||||
return int_type(EOF);
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t hash_step(std::size_t prev, Char c, key_char_traits<Char>)
|
||||
{
|
||||
return prev ^ (key_char_traits<Char>::to_lower(c) << 1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
using value_char_traits = std::char_traits<Char>;
|
||||
|
||||
BOOST_CONSTEXPR static char_type equality_sign = L'=';
|
||||
BOOST_CONSTEXPR static char_type delimiter = L';';
|
||||
|
||||
using native_handle_type = wchar_t*;
|
||||
using native_iterator = const wchar_t*;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
std::basic_string<wchar_t, value_char_traits<wchar_t>> get(
|
||||
basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
basic_cstring_ref<wchar_t, value_char_traits<wchar_t>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
|
||||
error_code & ec);
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
std::basic_string<char, value_char_traits<char>> get(
|
||||
basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void set(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
basic_cstring_ref<char, value_char_traits<char>> value,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL
|
||||
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec);
|
||||
|
||||
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
|
||||
struct native_handle_deleter
|
||||
{
|
||||
native_handle_deleter() = default;
|
||||
native_handle_deleter(const native_handle_deleter& ) = default;
|
||||
BOOST_PROCESS_V2_DECL void operator()(native_handle_type nh) const;
|
||||
|
||||
};
|
||||
|
||||
inline const char_type * dereference(native_iterator iterator) {return iterator;}
|
||||
BOOST_PROCESS_V2_DECL native_iterator next(native_iterator nh);
|
||||
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
|
||||
BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_code & ec);
|
||||
}
|
||||
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
18
include/boost/process/v2/detail/impl/environment.ipp
Normal file
18
include/boost/process/v2/detail/impl/environment.ipp
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright (c) 2022 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_V2_DETAIL_IMPL_ENVIRONMENT_IPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_PROCESS_V2_WINDOWS)
|
||||
#include <boost/process/v2/detail/impl/environment_win.ipp>
|
||||
#elif defined(BOOST_PROCESS_V2_POSIX)
|
||||
#include <boost/process/v2/detail/impl/environment_posix.ipp>
|
||||
#else
|
||||
#error Operating System not supported.
|
||||
#endif
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
|
||||
81
include/boost/process/v2/detail/impl/environment_posix.ipp
Normal file
81
include/boost/process/v2/detail/impl/environment_posix.ipp
Normal file
@@ -0,0 +1,81 @@
|
||||
//
|
||||
// process/this_process/detail/environment_posix.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
#include <boost/process/v2/environment.hpp>
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
basic_cstring_ref<char_type, value_char_traits<char>> get(
|
||||
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
auto res = ::getenv(key.c_str());
|
||||
if (res == nullptr)
|
||||
{
|
||||
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
|
||||
return {};
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
|
||||
error_code & ec)
|
||||
{
|
||||
if (::setenv(key.c_str(), value.c_str(), true))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
|
||||
{
|
||||
if (::unsetenv(key.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
native_handle_type load_native_handle() { return ::environ; }
|
||||
|
||||
|
||||
native_iterator next(native_iterator nh)
|
||||
{
|
||||
return nh + 1;
|
||||
}
|
||||
|
||||
native_iterator find_end(native_handle_type nh)
|
||||
{
|
||||
while (*nh != nullptr)
|
||||
nh++;
|
||||
return nh;
|
||||
}
|
||||
bool is_executable(const filesystem::path & p, error_code & ec)
|
||||
{
|
||||
return filesystem::is_regular_file(p, ec) && (::access(p.c_str(), X_OK) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
|
||||
142
include/boost/process/v2/detail/impl/environment_win.ipp
Normal file
142
include/boost/process/v2/detail/impl/environment_win.ipp
Normal file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// process/this_process/detail/environment_win.hpp
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
|
||||
//
|
||||
// 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_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
|
||||
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
|
||||
|
||||
|
||||
#include <boost/process/v2/detail/config.hpp>
|
||||
#include <boost/process/v2/detail/environment_win.hpp>
|
||||
#include <boost/process/v2/detail/impl/environment.ipp>
|
||||
#include <boost/process/v2/detail/last_error.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cwctype>
|
||||
#include <cstring>
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
#include <boost/process/v2/cstring_ref.hpp>
|
||||
#include <boost/process/v2/error.hpp>
|
||||
|
||||
BOOST_PROCESS_V2_BEGIN_NAMESPACE
|
||||
|
||||
namespace environment
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
std::basic_string<char_type, value_char_traits<char_type>> get(
|
||||
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
std::basic_string<char_type, value_char_traits<char_type>> buf;
|
||||
|
||||
std::size_t size = 0u;
|
||||
do
|
||||
{
|
||||
buf.resize(buf.size() + 4096);
|
||||
size = ::GetEnvironmentVariableW(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
|
||||
}
|
||||
while (size == buf.size());
|
||||
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), value.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
std::basic_string<char, value_char_traits<char>> get(
|
||||
basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
std::basic_string<char, value_char_traits<char>> buf;
|
||||
|
||||
std::size_t size = 0u;
|
||||
do
|
||||
{
|
||||
buf.resize(buf.size() + 4096);
|
||||
size = ::GetEnvironmentVariableA(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
|
||||
}
|
||||
while (size == buf.size());
|
||||
|
||||
buf.resize(size);
|
||||
|
||||
if (buf.size() == 0)
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void set(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
basic_cstring_ref<char, value_char_traits<char>> value,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), value.c_str()))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
|
||||
error_code & ec)
|
||||
{
|
||||
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
|
||||
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
|
||||
}
|
||||
|
||||
|
||||
native_handle_type load_native_handle() { return ::GetEnvironmentStringsW(); }
|
||||
void native_handle_deleter::operator()(native_handle_type nh) const
|
||||
{
|
||||
::FreeEnvironmentStringsW(nh);
|
||||
}
|
||||
|
||||
native_iterator next(native_iterator nh)
|
||||
{
|
||||
while (*nh != L'\0')
|
||||
nh++;
|
||||
return ++nh;
|
||||
}
|
||||
|
||||
|
||||
native_iterator find_end(native_handle_type nh)
|
||||
{
|
||||
while ((*nh != L'\0') || (*std::next(nh) != L'\0'))
|
||||
nh++;
|
||||
return ++nh;
|
||||
}
|
||||
|
||||
bool is_executable(const filesystem::path & pth, error_code & ec)
|
||||
{
|
||||
return filesystem::is_regular_file(pth, ec) && SHGetFileInfoW(pth.native().c_str(), 0,0,0, SHGFI_EXETYPE);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
BOOST_PROCESS_V2_END_NAMESPACE
|
||||
|
||||
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user