mirror of
https://github.com/boostorg/process.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
348 Commits
boost-1.76
...
osx-exit-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6ad7035e9 | ||
|
|
58586e420c | ||
|
|
7e5dd4075f | ||
|
|
3ad68a3f2a | ||
|
|
8a8ca8b7ab | ||
|
|
817128108a | ||
|
|
941e93b587 | ||
|
|
e827d14542 | ||
|
|
f218a6a6c1 | ||
|
|
11a0d0d7c1 | ||
|
|
fdfb5043cb | ||
|
|
e46a514629 | ||
|
|
36954338d8 | ||
|
|
a44fd24523 | ||
|
|
eb6b49c090 | ||
|
|
928674d2e3 | ||
|
|
894f371898 | ||
|
|
7ed1648032 | ||
|
|
a96f7a04e0 | ||
|
|
46b71d5e96 | ||
|
|
9f104634a9 | ||
|
|
c492c93062 | ||
|
|
12192d35d3 | ||
|
|
f741b0d120 | ||
|
|
211a3134b6 | ||
|
|
642bd7cf5c | ||
|
|
8df45b8f68 | ||
|
|
54479a7372 | ||
|
|
9761be99bb | ||
|
|
e5e898f363 | ||
|
|
9561ebad1c | ||
|
|
755a3ec78d | ||
|
|
5f80218655 | ||
|
|
3719df39cd | ||
|
|
67a2f97633 | ||
|
|
8b3e90234b | ||
|
|
8044857bb9 | ||
|
|
414d0d6b84 | ||
|
|
2c372461e8 | ||
|
|
2b436127ee | ||
|
|
c342762484 | ||
|
|
c2da58e548 | ||
|
|
aea22dbf6b | ||
|
|
084a85fc6e | ||
|
|
2171367d97 | ||
|
|
67a92df441 | ||
|
|
c773ee16cf | ||
|
|
274fc3163a | ||
|
|
44cae64d49 | ||
|
|
55e2460967 | ||
|
|
bcdd91188c | ||
|
|
e455a12e2c | ||
|
|
e8b5bf17f0 | ||
|
|
20510abc65 | ||
|
|
0058a9c69f | ||
|
|
a26f4fe3c5 | ||
|
|
ff5b383833 | ||
|
|
0379ee6668 | ||
|
|
193384a450 | ||
|
|
406cd3ecf3 | ||
|
|
c6951ff773 | ||
|
|
f2330c195a | ||
|
|
2ae279bd15 | ||
|
|
7a17af0f5c | ||
|
|
768944672f | ||
|
|
46acb247f5 | ||
|
|
08e3549713 | ||
|
|
029ad735fe | ||
|
|
03a348ebdd | ||
|
|
f289f26c87 | ||
|
|
8d9aa1e31d | ||
|
|
1873f34435 | ||
|
|
5f795d9e62 | ||
|
|
f17be678f2 | ||
|
|
b9fc531507 | ||
|
|
69c2c25729 | ||
|
|
8ab2332327 | ||
|
|
ea69cda6d8 | ||
|
|
6b75b4039f | ||
|
|
3c1beb40f6 | ||
|
|
e51970e3bb | ||
|
|
f3f8548dea | ||
|
|
4b7a00d4cf | ||
|
|
c11f31d77e | ||
|
|
3769ec01f4 | ||
|
|
af47f4677c | ||
|
|
cf14d54343 | ||
|
|
b81cac8042 | ||
|
|
c92cce3652 | ||
|
|
d270712fba | ||
|
|
7b6b93691f | ||
|
|
507768e230 | ||
|
|
502dc48753 | ||
|
|
402acc151a | ||
|
|
0503b0997c | ||
|
|
8d372cb510 | ||
|
|
bfb1ebb5bd | ||
|
|
c005adc8fc | ||
|
|
5cab462710 | ||
|
|
ccd46dc692 | ||
|
|
b3c8c3a8da | ||
|
|
4dd6f28094 | ||
|
|
d73f228469 | ||
|
|
ccd1717588 | ||
|
|
9a4aeab97e | ||
|
|
d66dce11bd | ||
|
|
fc38699a4b | ||
|
|
a859c5151c | ||
|
|
8c2f403841 | ||
|
|
6fb2702a79 | ||
|
|
6cd4244f05 | ||
|
|
0c42a58eac | ||
|
|
f269236d38 | ||
|
|
4b413d34f4 | ||
|
|
1403af769b | ||
|
|
964f6d3f7e | ||
|
|
bccf42a3ec | ||
|
|
70c7ae694f | ||
|
|
1fdd405a3f | ||
|
|
af2e884352 | ||
|
|
1fbd8bb5e1 | ||
|
|
09ba5e8d47 | ||
|
|
2c6304b563 | ||
|
|
e79c5f5edd | ||
|
|
7a9ab79162 | ||
|
|
0c1c6dfa90 | ||
|
|
4f9f4c398a | ||
|
|
e4a3e305b4 | ||
|
|
9d51e1cd32 | ||
|
|
f1302430cb | ||
|
|
6f0d6a2e24 | ||
|
|
57b67e0173 | ||
|
|
bbc7eb82e5 | ||
|
|
744e9d95b3 | ||
|
|
bc9a98787e | ||
|
|
0fdd448c67 | ||
|
|
5fcf5465ce | ||
|
|
1dc9d8689e | ||
|
|
dc915be11d | ||
|
|
d7df60938e | ||
|
|
765650aed3 | ||
|
|
f12bc25122 | ||
|
|
32a2c2297c | ||
|
|
3258e3a11c | ||
|
|
ba7e8db9bb | ||
|
|
3211afda4a | ||
|
|
d3f006acd4 | ||
|
|
99633a6e42 | ||
|
|
1e614ee43e | ||
|
|
0e3358705d | ||
|
|
27a35f452d | ||
|
|
8fff7283ed | ||
|
|
611dac143f | ||
|
|
8d93576b94 | ||
|
|
f703845011 | ||
|
|
abd052e09f | ||
|
|
a3304564c6 | ||
|
|
5865c6b449 | ||
|
|
4c872c0a0d | ||
|
|
feabbee098 | ||
|
|
a5b6e70c39 | ||
|
|
347fc68476 | ||
|
|
61ff12c8da | ||
|
|
bd8e81153c | ||
|
|
5fde6bec9f | ||
|
|
cf64f7dc6a | ||
|
|
8355c3e1b6 | ||
|
|
de797e388d | ||
|
|
fc33435f8b | ||
|
|
f45ec624db | ||
|
|
9682056278 | ||
|
|
a00115b454 | ||
|
|
3db86ac69f | ||
|
|
5ffb6bf8da | ||
|
|
2c5a38bfbe | ||
|
|
f28a6406ae | ||
|
|
7a1820d546 | ||
|
|
6bc5add9a7 | ||
|
|
f876ba81e6 | ||
|
|
e943f8fb9c | ||
|
|
bc55a93dce | ||
|
|
2eee42d5e6 | ||
|
|
2d2b124647 | ||
|
|
50986cc330 | ||
|
|
09f0a2c547 | ||
|
|
13af16bfec | ||
|
|
7745fdc687 | ||
|
|
d36f481392 | ||
|
|
011380c28a | ||
|
|
ebd4e723c3 | ||
|
|
b8108c508f | ||
|
|
ecf3dde88c | ||
|
|
4761b375d0 | ||
|
|
ae6a9e6639 | ||
|
|
2c35167d9b | ||
|
|
b68900ca1c | ||
|
|
ba7fe11193 | ||
|
|
b0da4ad10c | ||
|
|
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 | ||
|
|
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 |
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")
|
||||
34
.drone/drone.bat
Executable file
34
.drone/drone.bat
Executable file
@@ -0,0 +1,34 @@
|
||||
@ECHO ON
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
if "%DRONE_JOB_BUILDTYPE%" == "boost" (
|
||||
|
||||
echo '==================================> INSTALL'
|
||||
|
||||
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
|
||||
cp -prf boost-ci-cloned/ci .
|
||||
rm -rf boost-ci-cloned
|
||||
|
||||
REM source ci/travis/install.sh
|
||||
REM The contents of install.sh below:
|
||||
|
||||
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
|
||||
SET BOOST_CI_TARGET_BRANCH=%DRONE_COMMIT_BRANCH%
|
||||
SET BOOST_CI_SRC_FOLDER=%cd%
|
||||
|
||||
call ci\common_install.bat
|
||||
|
||||
echo '==================================> COMPILE'
|
||||
|
||||
REM set B2_TARGETS=libs/!SELF!/test libs/!SELF!/example
|
||||
set B2_TARGETS=libs/!SELF!/test
|
||||
|
||||
cd !BOOST_ROOT!
|
||||
call bootstrap.bat
|
||||
b2 headers
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
|
||||
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
|
||||
|
||||
REM not used
|
||||
|
||||
)
|
||||
199
.drone/drone.sh
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
|
||||
238
.github/workflows/ci.yml
vendored
Normal file
238
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
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-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-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-10
|
||||
- toolset: gcc-12
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
install: g++-12
|
||||
- toolset: clang
|
||||
compiler: clang++-3.9
|
||||
cxxstd: "11,14"
|
||||
os: ubuntu-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
|
||||
|
||||
alpine-linux:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:3.20.1
|
||||
steps:
|
||||
- name: Install packages
|
||||
run: apk add g++ git python3 linux-headers
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
./b2 -j3 libs/$LIBRARY/test toolset=gcc cxxstd=23 variant=debug,release
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: msvc-14.0
|
||||
cxxstd: "14,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.2
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2019
|
||||
- toolset: msvc-14.3
|
||||
cxxstd: "14,17,20,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: clang-win
|
||||
cxxstd: "14,17,latest"
|
||||
addrmd: 32,64
|
||||
os: windows-2022
|
||||
- toolset: gcc
|
||||
cxxstd: "11,14,17,2a"
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@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
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,4 +31,5 @@
|
||||
/notes.cpp
|
||||
/notes_p.txt
|
||||
.settings
|
||||
.DS_Store
|
||||
|
||||
|
||||
72
CMakeLists.txt
Normal file
72
CMakeLists.txt
Normal file
@@ -0,0 +1,72 @@
|
||||
# Generated by `boostdep --cmake process`
|
||||
# Copyright 2020 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_process
|
||||
src/detail/environment_posix.cpp
|
||||
src/detail/environment_win.cpp
|
||||
src/detail/last_error.cpp
|
||||
src/detail/process_handle_windows.cpp
|
||||
src/detail/throw_error.cpp
|
||||
src/detail/utf8.cpp
|
||||
src/ext/cmd.cpp
|
||||
src/ext/cwd.cpp
|
||||
src/ext/env.cpp
|
||||
src/ext/exe.cpp
|
||||
src/ext/proc_info.cpp
|
||||
src/posix/close_handles.cpp
|
||||
src/windows/default_launcher.cpp
|
||||
src/environment.cpp
|
||||
src/error.cpp
|
||||
src/pid.cpp
|
||||
src/shell.cpp)
|
||||
|
||||
add_library(Boost::process ALIAS boost_process)
|
||||
|
||||
target_include_directories(boost_process PUBLIC include)
|
||||
target_link_libraries(boost_process
|
||||
PUBLIC
|
||||
Boost::algorithm
|
||||
Boost::asio
|
||||
Boost::config
|
||||
Boost::core
|
||||
Boost::filesystem
|
||||
Boost::fusion
|
||||
Boost::iterator
|
||||
Boost::move
|
||||
Boost::optional
|
||||
Boost::system
|
||||
Boost::tokenizer
|
||||
Boost::type_index
|
||||
Boost::winapi
|
||||
)
|
||||
|
||||
target_compile_definitions(boost_process
|
||||
PRIVATE BOOST_PROCESS_SOURCE=1
|
||||
)
|
||||
|
||||
if (BOOST_PROCESS_USE_STD_FS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_USE_STD_FS=1 )
|
||||
else()
|
||||
target_link_libraries(boost_process PUBLIC Boost::filesystem)
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(boost_process PUBLIC ntdll shell32 advapi32 user32)
|
||||
endif()
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_DYN_LINK)
|
||||
else()
|
||||
target_compile_definitions(boost_process PUBLIC BOOST_PROCESS_STATIC_LINK)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
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.
|
||||
|
||||
47
build.jam
Normal file
47
build.jam
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright René Ferdinand Rivera Morell 2024
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
require-b2 5.2 ;
|
||||
|
||||
import feature : feature ;
|
||||
|
||||
feature boost.process.fs : boost std : optional propagated ;
|
||||
feature boost.process.disable-close-range : on off : optional ;
|
||||
|
||||
constant boost_dependencies :
|
||||
/boost/algorithm//boost_algorithm
|
||||
/boost/asio//boost_asio
|
||||
/boost/assert//boost_assert
|
||||
/boost/config//boost_config
|
||||
/boost/core//boost_core
|
||||
/boost/fusion//boost_fusion
|
||||
/boost/io//boost_io
|
||||
/boost/iterator//boost_iterator
|
||||
/boost/move//boost_move
|
||||
/boost/optional//boost_optional
|
||||
/boost/system//boost_system
|
||||
/boost/throw_exception//boost_throw_exception
|
||||
/boost/tokenizer//boost_tokenizer
|
||||
/boost/type_index//boost_type_index
|
||||
/boost/type_traits//boost_type_traits
|
||||
/boost/utility//boost_utility
|
||||
/boost/winapi//boost_winapi ;
|
||||
|
||||
project /boost/process
|
||||
: common-requirements
|
||||
<include>include
|
||||
: default-build
|
||||
<boost.process.fs>boost
|
||||
;
|
||||
|
||||
explicit
|
||||
[ alias boost_process : build//boost_process ]
|
||||
[ alias all : boost_process example example/v2 test ]
|
||||
;
|
||||
|
||||
call-if : boost-library process
|
||||
: install boost_process
|
||||
;
|
||||
|
||||
73
build/Jamfile
Normal file
73
build/Jamfile
Normal file
@@ -0,0 +1,73 @@
|
||||
# Copyright (c) 2024 Klemens D. Morgenstern
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
import os ;
|
||||
import feature ;
|
||||
import-search /boost/config/checks ;
|
||||
import config : requires ;
|
||||
|
||||
project : requirements
|
||||
<define>BOOST_ASIO_NO_DEPRECATED
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
|
||||
<toolset>msvc:<cxxflags>/bigobj
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>linux:<linkflags>-lpthread
|
||||
: source-location ../src
|
||||
: common-requirements
|
||||
<library>$(boost_dependencies)
|
||||
<boost.process.fs>std:<define>BOOST_PROCESS_USE_STD_FS=1
|
||||
;
|
||||
|
||||
alias process_sources
|
||||
: detail/environment_posix.cpp
|
||||
detail/environment_win.cpp
|
||||
detail/last_error.cpp
|
||||
detail/process_handle_windows.cpp
|
||||
detail/throw_error.cpp
|
||||
detail/utf8.cpp
|
||||
ext/cmd.cpp
|
||||
ext/cwd.cpp
|
||||
ext/env.cpp
|
||||
ext/exe.cpp
|
||||
ext/proc_info.cpp
|
||||
posix/close_handles.cpp
|
||||
windows/default_launcher.cpp
|
||||
environment.cpp
|
||||
error.cpp
|
||||
pid.cpp
|
||||
shell.cpp
|
||||
;
|
||||
|
||||
lib shell32 ;
|
||||
lib advapi32 ;
|
||||
lib ntdll ;
|
||||
lib user32 ;
|
||||
lib ws2_32 ;
|
||||
|
||||
lib kvm ;
|
||||
lib procstat ;
|
||||
|
||||
lib boost_process
|
||||
: process_sources
|
||||
: requirements <define>BOOST_PROCESS_SOURCE=1
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
<boost.process.disable-close-range>on:<define>BOOST_PROCESS_V2_POSIX_FORCE_DISABLE_CLOSE_RANGE=1
|
||||
<target-os>windows:<library>shell32
|
||||
<target-os>windows:<library>user32
|
||||
<target-os>windows:<library>ntdll
|
||||
<target-os>windows:<library>advapi32
|
||||
<target-os>windows:<library>ws2_32
|
||||
<target-os>bsd:<library>kvm
|
||||
<target-os>freebsd:<library>kvm
|
||||
<target-os>freebsd:<library>procstat
|
||||
<target-os>netbsd:<library>kvm
|
||||
<target-os>openbsd:<library>kvm
|
||||
<target-os>solaris:<library>kvm
|
||||
: usage-requirements
|
||||
<link>shared:<define>BOOST_PROCESS_DYN_LINK=1
|
||||
<boost.process.fs>boost:<library>/boost/filesystem//boost_filesystem
|
||||
;
|
||||
@@ -14,24 +14,28 @@ using doxygen ;
|
||||
|
||||
local images = [ glob images/*.svg ] ;
|
||||
install images : $(images) : <location>html/boost_process ;
|
||||
install images_glob : $(images) : <location>$(BOOST_ROOT)/doc/html/boost_process ;
|
||||
install images_glob : $(images) : <location>$(BOOST_ROOT)/doc/html/boost_process ;
|
||||
|
||||
import type ;
|
||||
type.register XMLPROCESSWORKAROUND : : XML ;
|
||||
import generators ;
|
||||
generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
|
||||
generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
|
||||
|
||||
xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ;
|
||||
xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ;
|
||||
xmlprocessworkaround posix_pseudocode : v1/posix_pseudocode.xml ;
|
||||
xmlprocessworkaround windows_pseudocode : v1/windows_pseudocode.xml ;
|
||||
|
||||
path-constant INCLUDES : ../include ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
../../../boost/process.hpp
|
||||
[ glob ../../../boost/process/*.hpp ]
|
||||
doxygen reference_v1
|
||||
:
|
||||
$(INCLUDES)/boost/process/v1.hpp
|
||||
[ glob $(INCLUDES)/boost/process/v1/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
|
||||
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
|
||||
<doxygen:param>"PREDEFINED=\\
|
||||
BOOST_PROCESS_DOXYGEN=1 \\
|
||||
BOOST_PROCESS_V1_INLINE=
|
||||
"
|
||||
<doxygen:param>HIDE_UNDOC_CLASSES=YES
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
<doxygen:param>EXAMPLE_PATH=.
|
||||
@@ -42,11 +46,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_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_PROCESS_V2_INLINE= \\
|
||||
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_v1
|
||||
<dependency>reference_v2
|
||||
<dependency>images
|
||||
<dependency>images_glob
|
||||
<xsl:param>boost.root=../../../..
|
||||
@@ -56,7 +98,7 @@ boostbook standalone
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: standalone/<format>docbook
|
||||
:
|
||||
:
|
||||
: <dependency>images_glob
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
|
||||
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
|
||||
<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (pid == -1) //fork error
|
||||
{
|
||||
<methodname alt="boost::process::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>()
|
||||
}
|
||||
else if (pid == 0) //child process
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
|
||||
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
|
||||
auto ec = <functionname alt="boost::process::extend::get_last_error">get_last_error</functionname>();
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here the error is send to the father process interally
|
||||
|
||||
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
|
||||
return <classname alt="boost::process::child">child</classname>(); //for C++ compliance
|
||||
}
|
||||
|
||||
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here, we read the the error from the child process
|
||||
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
</programlisting>
|
||||
@@ -11,11 +11,8 @@
|
||||
]
|
||||
]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include concepts.qbk]
|
||||
[include tutorial.qbk]
|
||||
[include design.qbk]
|
||||
[include extend.qbk]
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[note Process v1 will be deprecated in the next release (1.88). Use v2 for new projects.]
|
||||
|
||||
[include v1.qbk]
|
||||
[include v2.qbk]
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
11
doc/v1.qbk
Normal file
11
doc/v1.qbk
Normal file
@@ -0,0 +1,11 @@
|
||||
[section:v1 Process V1]
|
||||
|
||||
[include v1/introduction.qbk]
|
||||
[include v1/concepts.qbk]
|
||||
[include v1/tutorial.qbk]
|
||||
[include v1/design.qbk]
|
||||
[include v1/extend.qbk]
|
||||
[include v1/faq.qbk]
|
||||
[xinclude reference_v1.xml]
|
||||
|
||||
[endsect]
|
||||
@@ -35,13 +35,13 @@ In this library the following functions are used for the creation of unnamed pip
|
||||
As the name suggests, named pipes have a string identifier. This means that a
|
||||
handle to them can be obtained with the identifier, too.
|
||||
|
||||
The implementation on posix uses [@(http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
|
||||
The implementation on posix uses [@http://pubs.opengroup.org/onlinepubs/009695399/functions/mkfifo.html fifos],
|
||||
which means, that the named pipe behaves like a file.
|
||||
|
||||
Windows does provide a facility called [@https://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx named pipes],
|
||||
which also have file-like names, but are in a different scope than the actual file system.
|
||||
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchrounous communication on windows.]
|
||||
[note The main reason named pipes are part of this library, is because they need to be internally used for asynchronous communication on windows.]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -75,15 +75,15 @@ but the one of the launching process, not the one passed to the child process.]
|
||||
The simplest form to extend functionality is to provide another handler, which
|
||||
will be called on the respective events on process launching. The names are:
|
||||
|
||||
*`boost::process::on_setup`
|
||||
*`boost::process::on_error`
|
||||
*`boost::process::on_success`
|
||||
*`boost::process::v1::on_setup`
|
||||
*`boost::process::v1::on_error`
|
||||
*`boost::process::v1::on_success`
|
||||
|
||||
|
||||
As an example:
|
||||
|
||||
```
|
||||
child c("ls", on_setup([](){cout << "On Setup" << endl;});
|
||||
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
|
||||
```
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
[def __on_exit__ [globalref boost::process::on_exit on_exit]]
|
||||
[def __on_success__ [globalref boost::process::extend::on_success ex::on_success]]
|
||||
[def __child__ [classref boost::process::child child]]
|
||||
[def __handler__ [classref boost::process::extend::handler handler]]
|
||||
[def __on_success__ [memberref boost::process::extend::handler::on_success on_success]]
|
||||
[def __posix_executor__ [classref boost::process::extend::posix_executor ex::posix_executor]]
|
||||
[def __windows_executor__ [classref boost::process::extend::windows_executor ex::windows_executor]]
|
||||
[def __on_exit__ [globalref boost::process::v1::on_exit on_exit]]
|
||||
[def __on_success__ [globalref boost::process::v1::extend::on_success ex::on_success]]
|
||||
[def __child__ [classref boost::process::v1::child child]]
|
||||
[def __handler__ [classref boost::process::v1::extend::handler handler]]
|
||||
[def __on_success__ [memberref boost::process::v1::extend::handler::on_success on_success]]
|
||||
[def __posix_executor__ [classref boost::process::v1::extend::posix_executor ex::posix_executor]]
|
||||
[def __windows_executor__ [classref boost::process::v1::extend::windows_executor ex::windows_executor]]
|
||||
[def __io_context__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_context.html boost::asio::io_context]]
|
||||
[def __require_io_context__ [classref boost::process::extend::require_io_context ex::require_io_context]]
|
||||
[def __async_handler__ [classref boost::process::extend::async_handler ex::async_handler]]
|
||||
[def __get_io_context__ [funcref boost::process::extend::get_io_context ex::get_io_context]]
|
||||
[def __require_io_context__ [classref boost::process::v1::extend::require_io_context ex::require_io_context]]
|
||||
[def __async_handler__ [classref boost::process::v1::extend::async_handler ex::async_handler]]
|
||||
[def __get_io_context__ [funcref boost::process::v1::extend::get_io_context ex::get_io_context]]
|
||||
|
||||
[section:extend Extensions]
|
||||
To extend the library, the header [headerref boost/process/extend.hpp extend] is provided.
|
||||
@@ -16,7 +16,7 @@ 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 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
|
||||
If a class inherits [classref boost::process::v1::extend::handler] it will be regarded as an initializer and thus directly put into the sequence
|
||||
the executor gets passed.
|
||||
|
||||
[section:structure Structure]
|
||||
@@ -24,9 +24,9 @@ the executor gets passed.
|
||||
The executor calls different handlers of the initializers during the process launch.
|
||||
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]
|
||||
* [globalref boost::process::extend::on_success on_success]
|
||||
* [globalref boost::process::v1::extend::on_setup on_setup]
|
||||
* [globalref boost::process::v1::extend::on_error on_error]
|
||||
* [globalref boost::process::v1::extend::on_success on_success]
|
||||
|
||||
'''
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
@@ -34,11 +34,11 @@ The basic structure consists of three functions, as given below:
|
||||
|
||||
Additionally posix provides three more handlers, listed below:
|
||||
|
||||
* [globalref boost::process::extend::on_fork_error on_fork_error]
|
||||
* [globalref boost::process::extend::on_exec_setup on_exec_setup]
|
||||
* [globalref boost::process::extend::on_exec_error on_exec_error]
|
||||
* [globalref boost::process::v1::extend::on_fork_error on_fork_error]
|
||||
* [globalref boost::process::v1::extend::on_exec_setup on_exec_setup]
|
||||
* [globalref boost::process::v1::extend::on_exec_error on_exec_error]
|
||||
|
||||
For more information see the reference of [classref boost::process::extend::posix_executor posix_executor].
|
||||
For more information see the reference of [classref boost::process::v1::extend::posix_executor posix_executor].
|
||||
|
||||
[endsect]
|
||||
[section:simple Simple extensions]
|
||||
@@ -55,8 +55,8 @@ __child__ c("foo", __on_success__=[](auto & exec) {std::cout << "hello world" <<
|
||||
|
||||
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].
|
||||
To see which members the executor has, refer to [classref boost::process::v1::extend::windows_executor windows_executor]
|
||||
and [classref boost::process::v1::extend::posix_executor posix_executor].
|
||||
|
||||
[note Combined with __on_exit__ this can also handle the process exit.]
|
||||
|
||||
@@ -67,7 +67,7 @@ and [classref boost::process::extend::posix_executor posix_executor].
|
||||
[section:handler Handler Types]
|
||||
|
||||
Since the previous example is in a functional style, it is not very reusable.
|
||||
To solve that problem, the [classref boost::process::extend::handler handler] has an alias in the `boost::process::extend` namespace, to be inherited.
|
||||
To solve that problem, the [classref boost::process::v1::extend::handler handler] has an alias in the `boost::process::v1::extend` namespace, to be inherited.
|
||||
So let's implement the hello world example in a class.
|
||||
|
||||
```
|
||||
@@ -86,7 +86,7 @@ __child__ c("foo", hello_world());
|
||||
|
||||
[note The implementation is done via overloading, not overriding.]
|
||||
|
||||
Every handler not implemented defaults 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::v1::extend::handler handler], where an empty handler is defined for each event.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -108,11 +108,11 @@ struct async_foo : __handler__, __require_io_context__
|
||||
}
|
||||
};
|
||||
```
|
||||
[note Inheriting [globalref boost::process::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::system system] provides one.]
|
||||
[note Inheriting [globalref boost::process::v1::extend::require_io_context require_io_context] is necessary, so [funcref boost::process::v1::system system] provides one.]
|
||||
|
||||
Additionally the handler can provide a function that is invoked when the child process exits. This is done through __async_handler__.
|
||||
|
||||
[note [globalref boost::process::extend::async_handler async_handler] implies [globalref boost::process::extend::require_io_context require_io_context] .]
|
||||
[note [globalref boost::process::v1::extend::async_handler async_handler] implies [globalref boost::process::v1::extend::require_io_context require_io_context] .]
|
||||
|
||||
```
|
||||
struct async_bar : __handler, __async_handler__
|
||||
@@ -131,7 +131,7 @@ struct async_bar : __handler, __async_handler__
|
||||
```
|
||||
|
||||
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::extend::async_handler async_handler] is inherited. ]
|
||||
[caution `on_exit_handler` does not default and is always required when [classref boost::process::v1::extend::async_handler async_handler] is inherited. ]
|
||||
|
||||
[caution `on_exit_handler` uses `boost::asio::signal_set` to listen for SIGCHLD on posix. The application must not also register a signal handler for SIGCHLD using functions such as `signal()` or `sigaction()` (but using `boost::asio::signal_set` is fine). ]
|
||||
|
||||
@@ -156,7 +156,7 @@ auto set_error = [](auto & exec)
|
||||
__child__ c("foo", on_setup=set_error);
|
||||
```
|
||||
|
||||
Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::process_error process_error].
|
||||
Since we do not specify the error-handling mode in this example, this will throw [classref boost::process::v1::process_error process_error].
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -10,15 +10,15 @@ Boost.Process is a library to manage system processes. It can be used to:
|
||||
|
||||
Here's a simple example of how to start a program with Boost.Process:
|
||||
|
||||
[def ipstream [classref boost::process::ipstream ipstream]]
|
||||
[def system [funcref boost::process::system system]]
|
||||
[def std_out [globalref boost::process::std_out std_out]]
|
||||
[def child [globalref boost::process::child child]]
|
||||
[def ipstream [classref boost::process::v1::ipstream ipstream]]
|
||||
[def system [funcref boost::process::v1::system system]]
|
||||
[def std_out [globalref boost::process::v1::std_out std_out]]
|
||||
[def child [globalref boost::process::v1::child child]]
|
||||
[def boost/process.hpp [headerref boost/process.hpp boost/process.hpp]]
|
||||
[def std::string [@http://en.cppreference.com/w/cpp/string/basic_string std::string]]
|
||||
[def std::getline [@http://en.cppreference.com/w/cpp/string/basic_string/getline std::getline]]
|
||||
|
||||
[import ../example/intro.cpp]
|
||||
[import ../../example/intro.cpp]
|
||||
[intro]
|
||||
|
||||
[endsect]
|
||||
60
doc/v1/posix_pseudocode.xml
Normal file
60
doc/v1/posix_pseudocode.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
|
||||
pid = <ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html">fork()</ulink>
|
||||
<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (pid == -1) //fork error
|
||||
{
|
||||
<methodname alt="boost::process::v1::extend::posix_executor::set_error">set_error</methodname>(<functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_fork_error">on_fork_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>()
|
||||
}
|
||||
else if (pid == 0) //child process
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_exec_setup">on_exec_setup</methodname>(*this);
|
||||
<ulink url="http://pubs.opengroup.org/onlinepubs/009695399/functions/exec.html">execve</ulink>(exe, cmd_line, env);
|
||||
auto ec = <functionname alt="boost::process::v1::extend::get_last_error">get_last_error</functionname>();
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here the error is sent to the father process internally
|
||||
|
||||
<ulink url="http://en.cppreference.com/w/cpp/utility/program/exit">std::exit</ulink>(<ulink url="http://en.cppreference.com/w/c/program/EXIT_status">EXIT_FAILURE</ulink>);
|
||||
return <classname alt="boost::process::v1::child">child</classname>(); //for C++ compliance
|
||||
}
|
||||
|
||||
<classname alt="boost::process::v1::child">child</classname> c(pid, exit_code);
|
||||
|
||||
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::posix_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
</programlisting>
|
||||
@@ -1,49 +1,49 @@
|
||||
[def bp::system [funcref boost::process::system bp::system]]
|
||||
[def bp::async_system [funcref boost::process::async_system bp::async_system]]
|
||||
[def bp::spawn [funcref boost::process::spawn bp::spawn]]
|
||||
[def bp::child [classref boost::process::child bp::child]]
|
||||
[def bp::cmd [classref boost::process::cmd bp::cmd]]
|
||||
[def bp::group [classref boost::process::group bp::group]]
|
||||
[def bp::ipstream [classref boost::process::ipstream bp::ipstream]]
|
||||
[def bp::opstream [classref boost::process::opstream bp::opstream]]
|
||||
[def bp::pstream [classref boost::process::pstream bp::pstream]]
|
||||
[def bp::pipe [classref boost::process::pipe bp::pipe]]
|
||||
[def bp::async_pipe [classref boost::process::async_pipe bp::async_pipe]]
|
||||
[def bp::search_path [funcref boost::process::search_path bp::search_path]]
|
||||
[def bp::system [funcref boost::process::v1::system bp::system]]
|
||||
[def bp::async_system [funcref boost::process::v1::async_system bp::async_system]]
|
||||
[def bp::spawn [funcref boost::process::v1::spawn bp::spawn]]
|
||||
[def bp::child [classref boost::process::v1::child bp::child]]
|
||||
[def bp::cmd [classref boost::process::v1::cmd bp::cmd]]
|
||||
[def bp::group [classref boost::process::v1::group bp::group]]
|
||||
[def bp::ipstream [classref boost::process::v1::ipstream bp::ipstream]]
|
||||
[def bp::opstream [classref boost::process::v1::opstream bp::opstream]]
|
||||
[def bp::pstream [classref boost::process::v1::pstream bp::pstream]]
|
||||
[def bp::pipe [classref boost::process::v1::pipe bp::pipe]]
|
||||
[def bp::async_pipe [classref boost::process::v1::async_pipe bp::async_pipe]]
|
||||
[def bp::search_path [funcref boost::process::v1::search_path bp::search_path]]
|
||||
[def boost_org [@www.boost.org "www.boost.org"]]
|
||||
[def std::system [@http://en.cppreference.com/w/cpp/utility/program/system std::system]]
|
||||
[def child_running [memberref boost::process::child::running running]]
|
||||
[def child_wait [memberref boost::process::child::wait wait]]
|
||||
[def child_wait_for [memberref boost::process::child::wait_for wait_for]]
|
||||
[def child_exit_code [memberref boost::process::child::exit_code exit_code]]
|
||||
[def group_wait_for [memberref boost::process::group::wait_for wait_for]]
|
||||
[def bp::on_exit [globalref boost::process::on_exit bp::on_exit]]
|
||||
[def bp::null [globalref boost::process::null bp::null]]
|
||||
[def child_terminate [memberref boost::process::child::terminate terminate]]
|
||||
[def group_terminate [memberref boost::process::group::terminate terminate]]
|
||||
[def group_wait [memberref boost::process::group::wait wait]]
|
||||
[def bp::std_in [globalref boost::process::std_in bp::std_in]]
|
||||
[def bp::std_out [globalref boost::process::std_out bp::std_out]]
|
||||
[def bp::std_err [globalref boost::process::std_err bp::std_err]]
|
||||
[def child_running [memberref boost::process::v1::child::running running]]
|
||||
[def child_wait [memberref boost::process::v1::child::wait wait]]
|
||||
[def child_wait_for [memberref boost::process::v1::child::wait_for wait_for]]
|
||||
[def child_exit_code [memberref boost::process::v1::child::exit_code exit_code]]
|
||||
[def group_wait_for [memberref boost::process::v1::group::wait_for wait_for]]
|
||||
[def bp::on_exit [globalref boost::process::v1::on_exit bp::on_exit]]
|
||||
[def bp::null [globalref boost::process::v1::null bp::null]]
|
||||
[def child_terminate [memberref boost::process::v1::child::terminate terminate]]
|
||||
[def group_terminate [memberref boost::process::v1::group::terminate terminate]]
|
||||
[def group_wait [memberref boost::process::v1::group::wait wait]]
|
||||
[def bp::std_in [globalref boost::process::v1::std_in bp::std_in]]
|
||||
[def bp::std_out [globalref boost::process::v1::std_out bp::std_out]]
|
||||
[def bp::std_err [globalref boost::process::v1::std_err bp::std_err]]
|
||||
[def io_service [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/io_service.html boost::asio::io_service]]
|
||||
[def asio_buffer [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html boost::asio::buffer]]
|
||||
[def asio_async_read [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_read.html boost::asio::async_read]]
|
||||
[def bp::environment [classref boost::process::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::basic_native_environment bp::native_environment]]
|
||||
[def bp::environment [classref boost::process::v1::basic_environment bp::environment]]
|
||||
[def bp::native_environment [classref boost::process::v1::basic_native_environment bp::native_environment]]
|
||||
[def boost::this_process::environment [funcref boost::this_process::environment boost::this_process::environment]]
|
||||
[def std::chrono::seconds [@http://en.cppreference.com/w/cpp/chrono/duration std::chrono::seconds]]
|
||||
[def std::vector [@http://en.cppreference.com/w/cpp/container/vector std::vector]]
|
||||
|
||||
[def __wait_for__ [memberref boost::process::child::wait_for wait_for]]
|
||||
[def __wait_until__ [memberref boost::process::child::wait_until wait_until]]
|
||||
[def __detach__ [memberref boost::process::child::detach detach]]
|
||||
[def __wait_for__ [memberref boost::process::v1::child::wait_for wait_for]]
|
||||
[def __wait_until__ [memberref boost::process::v1::child::wait_until wait_until]]
|
||||
[def __detach__ [memberref boost::process::v1::child::detach detach]]
|
||||
|
||||
[def __reference__ [link process.reference reference]]
|
||||
[def __concepts__ [link boost_process.concepts concepts]]
|
||||
|
||||
[def boost::asio::yield_context [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/yield_context.html boost::asio::yield_context]]
|
||||
[def boost::asio::coroutine [@http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/coroutine.html boost::asio::coroutine]]
|
||||
[def bp::env [globalref boost::process::env bp::env]]
|
||||
[def bp::env [globalref boost::process::v1::env bp::env]]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
@@ -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::v1::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
boost::process::v1::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
@@ -93,28 +93,28 @@ 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::v1::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
|
||||
int result = bp::system(p, "main.cpp");
|
||||
```
|
||||
|
||||
[note [funcref boost::process::search_path search_path] will search for any executable with that name.
|
||||
[note [funcref boost::process::v1::search_path search_path] will search for any executable with that name.
|
||||
This also includes to add a file suffix on windows, such as `.exe` or `.bat`.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:launch_mode Launch functions]
|
||||
|
||||
Given that our example used the [funcref boost::process::system system] function,
|
||||
Given that our example used the [funcref boost::process::v1::system system] function,
|
||||
our program will wait until the child process is completed. This may be unwanted,
|
||||
especially since compiling can take a while.
|
||||
|
||||
In order to avoid that, boost.process provides several ways to launch a process.
|
||||
Besides the already mentioned [funcref boost::process::system system] function and its
|
||||
asynchronous version [funcref boost::process::async_system async_system],
|
||||
we can also use the [funcref boost::process::spawn spawn] function or the
|
||||
[classref boost::process::child child] class.
|
||||
Besides the already mentioned [funcref boost::process::v1::system system] function and its
|
||||
asynchronous version [funcref boost::process::v1::async_system async_system],
|
||||
we can also use the [funcref boost::process::v1::spawn spawn] function or the
|
||||
[classref boost::process::v1::child child] class.
|
||||
|
||||
The [funcref boost::process::spawn spawn] function launches a process and
|
||||
The [funcref boost::process::v1::spawn spawn] function launches a process and
|
||||
immediately detaches it, so no handle will be returned and the process will be ignored.
|
||||
This is not what we need for compiling, but maybe we want to entertain the user,
|
||||
while compiling:
|
||||
@@ -124,7 +124,7 @@ bp::spawn(bp::search_path("chrome"), boost_org);
|
||||
```
|
||||
|
||||
Now for the more sensible approach for compiling: a non-blocking execution.
|
||||
To implement that, we directly call the constructor of [classref boost::process::child child].
|
||||
To implement that, we directly call the constructor of [classref boost::process::v1::child child].
|
||||
|
||||
```
|
||||
bp::child c(bp::search_path("g++"), "main.cpp");
|
||||
@@ -189,9 +189,9 @@ Now, let's take a more visual example for reading data.
|
||||
which reads the outline, i.e. a list of all entry points, of a binary.
|
||||
Every entry point will be put into a single line, and we will use a pipe to read it.
|
||||
At the end an empty line is appended, which we use as the indication to stop reading.
|
||||
Boost.process provides the pipestream ([classref boost::process::ipstream ipstream],
|
||||
[classref boost::process::opstream opstream], [classref boost::process::pstream pstream]) to
|
||||
wrap around the [classref boost::process::pipe pipe] and provide an implementation of the
|
||||
Boost.process provides the pipestream ([classref boost::process::v1::ipstream ipstream],
|
||||
[classref boost::process::v1::opstream opstream], [classref boost::process::v1::pstream pstream]) to
|
||||
wrap around the [classref boost::process::v1::pipe pipe] and provide an implementation of the
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_istream std::istream],
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_ostream std::ostream] and
|
||||
[@http://en.cppreference.com/w/cpp/io/basic_iostream std::iostream] interface.
|
||||
@@ -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::v1::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
|
||||
@@ -267,8 +267,8 @@ This forwards the data from `nm` to `c++filt` without your process needing to do
|
||||
|
||||
Boost.process allows the usage of boost.asio to implement asynchronous I/O.
|
||||
If you are familiar with [@http://www.boost.org/doc/libs/release/libs/asio/ boost.asio] (which we highly recommend),
|
||||
you can use [classref boost::process::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::pipe pipe] as shown above.
|
||||
you can use [classref boost::process::v1::async_pipe async_pipe] which is implemented
|
||||
as an I/O-Object and can be used like [classref boost::process::v1::pipe pipe] as shown above.
|
||||
|
||||
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.
|
||||
@@ -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::v1::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.
|
||||
@@ -348,7 +348,7 @@ and use the following code, the `gcc` process will still run afterwards:
|
||||
|
||||
```
|
||||
bp::child c("make");
|
||||
if (!c.child_wait_for(std::chrono::seconds(10)) //give it 10 seconds
|
||||
if (!c.child_wait_for(std::chrono::seconds(10))) //give it 10 seconds
|
||||
c.child_terminate(); //then terminate
|
||||
```
|
||||
|
||||
@@ -357,14 +357,14 @@ So in order to also terminate `gcc` we can use a group.
|
||||
```
|
||||
bp::group g;
|
||||
bp::child c("make", g);
|
||||
if (!g.group_wait_for(std::chrono::seconds(10))
|
||||
if (!g.group_wait_for(std::chrono::seconds(10)))
|
||||
g.group_terminate();
|
||||
|
||||
c.child_wait(); //to avoid a zombie process & get the exit code
|
||||
```
|
||||
|
||||
Now given the example, we still call child_wait to avoid a zombie process.
|
||||
An easier solution for that might be to use [funcref boost::process::spawn spawn].
|
||||
An easier solution for that might be to use [funcref boost::process::v1::spawn spawn].
|
||||
|
||||
|
||||
To put two processes into one group, the following code suffices. Spawn already
|
||||
@@ -412,7 +412,7 @@ bp::system("stuff", env_);
|
||||
```
|
||||
|
||||
A more convenient way to modify the environment for the child is the
|
||||
[globalref boost::process::env env] property, which can be used in the example as following:
|
||||
[globalref boost::process::v1::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"});
|
||||
42
doc/v1/windows_pseudocode.xml
Normal file
42
doc/v1/windows_pseudocode.xml
Normal file
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
|
||||
exe,
|
||||
cmd_line,
|
||||
proc_attrs,
|
||||
thread_attrs,
|
||||
creation_flags,
|
||||
env,
|
||||
work_dir,
|
||||
startup_info,
|
||||
proc_info);
|
||||
|
||||
<classname alt="boost::process::v1::child">child</classname> c(proc_info, exit_code);
|
||||
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because an on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::v1::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::v1::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::v1::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
|
||||
</programlisting>
|
||||
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 recommended to use the environment types,
|
||||
as to have the right value comparisons.
|
||||
|
||||
To note is the `find_executable` functions, which searches in an environment for an executable.
|
||||
|
||||
```
|
||||
// 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++");
|
||||
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
|
||||
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
86
doc/v2/introduction.qbk
Normal file
86
doc/v2/introduction.qbk
Normal file
@@ -0,0 +1,86 @@
|
||||
[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 addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
|
||||
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
|
||||
exe-args that can be randomly spread out.
|
||||
|
||||
[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: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::error_code ec;
|
||||
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
|
||||
```
|
||||
|
||||
The launcher will call certain functions on the initializer if they're present, as documented below.
|
||||
The initializer are used to modify the process behaviour.
|
||||
|
||||
[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_initializer
|
||||
{
|
||||
// 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 occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occurred when forking, in addition to on_error.
|
||||
template<typename Launcher>
|
||||
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
|
||||
const error_code & ec);
|
||||
|
||||
|
||||
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
|
||||
template<typename Launcher>
|
||||
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
|
||||
// called after a failed call to execve from the child process.
|
||||
template<typename Launcher>
|
||||
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
};
|
||||
```
|
||||
|
||||
The call sequence on success:
|
||||
'''
|
||||
<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 straight 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 occurred during setup or process creation
|
||||
template<typename Launcher>
|
||||
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
|
||||
const error_code & ec);
|
||||
|
||||
// called after successful process creation
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
[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]
|
||||
123
doc/v2/quickstart.qbk
Normal file
123
doc/v2/quickstart.qbk
Normal file
@@ -0,0 +1,123 @@
|
||||
[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 additional information about the process.
|
||||
This is called the `native_exit_code`.
|
||||
|
||||
|
||||
The `.running()` function can be used to detect if the process is still active.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:signal Signalling the subprocess]
|
||||
|
||||
The parent process can signal the subprocess demanding certain actions.
|
||||
|
||||
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
|
||||
This is the only reliable & portable way to end a subprocess.
|
||||
|
||||
```
|
||||
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` functions 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 timeout{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{ctx};
|
||||
|
||||
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]
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<programlisting>
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_setup">on_setup</methodname>(*this);
|
||||
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
int err_code = <ulink url="https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425.aspx">CreateProcess</ulink>(
|
||||
exe,
|
||||
cmd_line,
|
||||
proc_attrs,
|
||||
thread_attrs,
|
||||
creation_flags,
|
||||
env,
|
||||
work_dir,
|
||||
startup_info,
|
||||
proc_info);
|
||||
|
||||
<classname alt="boost::process::child">child</classname> c(proc_info, exit_code);
|
||||
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
else
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
|
||||
|
||||
//now we check again, because a on_success handler might've errored.
|
||||
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
|
||||
{
|
||||
for (auto & s : seq)
|
||||
s.<methodname alt="boost::process::extend::handler::on_error">on_error</methodname>(*this, <methodname alt="boost::process::extend::windows_executor::error">error</methodname>());
|
||||
return <classname alt="boost::process::child">child</classname>();
|
||||
}
|
||||
else
|
||||
return c;
|
||||
|
||||
</programlisting>
|
||||
@@ -8,7 +8,7 @@
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project : requirements
|
||||
<include>../../..
|
||||
<library>/boost/process//boost_process
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
;
|
||||
|
||||
@@ -22,7 +22,7 @@ int main()
|
||||
bp::std_in < bp::null //null in
|
||||
);
|
||||
|
||||
boost::filesystem::path p = "input.txt";
|
||||
boost::process::v1::filesystem::path p = "input.txt";
|
||||
|
||||
bp::system(
|
||||
"test.exe",
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/extend.hpp>
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -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/v1/filesystem.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
@@ -19,9 +19,9 @@ int main()
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
|
||||
boost::filesystem::path exe = "test.exe";
|
||||
boost::process::v1::filesystem::path exe = "test.exe";
|
||||
bp::system(
|
||||
boost::filesystem::absolute(exe),
|
||||
boost::process::v1::filesystem::absolute(exe),
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
}
|
||||
|
||||
15
example/v2/Jamfile.jam
Normal file
15
example/v2/Jamfile.jam
Normal file
@@ -0,0 +1,15 @@
|
||||
# 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
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<link>static
|
||||
;
|
||||
|
||||
import testing ;
|
||||
|
||||
exe intro : intro.cpp ;
|
||||
exe intro_popen : intro_popen.cpp : <boost.process.fs>boost ;
|
||||
39
example/v2/intro.cpp
Normal file
39
example/v2/intro.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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)
|
||||
|
||||
//[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 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)
|
||||
|
||||
//[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,7 +8,8 @@
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/process/windows.hpp>
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
#include <boost/process/v1/windows.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <windows.h>
|
||||
@@ -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; })
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,24 +19,16 @@
|
||||
* boost.process header files.
|
||||
*/
|
||||
|
||||
#include <boost/process/args.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/async_system.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/cmd.hpp>
|
||||
#include <boost/process/env.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/exe.hpp>
|
||||
#include <boost/process/group.hpp>
|
||||
#include <boost/process/handles.hpp>
|
||||
#include <boost/process/io.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/search_path.hpp>
|
||||
#include <boost/process/spawn.hpp>
|
||||
#include <boost/process/system.hpp>
|
||||
#include <boost/process/start_dir.hpp>
|
||||
#if !defined(BOOST_PROCESS_VERSION)
|
||||
#define BOOST_PROCESS_VERSION 1
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_VERSION == 1
|
||||
#include <boost/process/v1.hpp>
|
||||
#elif BOOST_PROCESS_VERSION == 2
|
||||
#include <boost/process/v2.hpp>
|
||||
#else
|
||||
#error "Unknown boost process version"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,279 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_ARGS_HPP
|
||||
#define BOOST_PROCESS_ARGS_HPP
|
||||
|
||||
/** \file boost/process/args.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::args">args</globalname>\endxmlonly property. It also provides the
|
||||
* alternative name \xmlonly <globalname alt="boost::process::argv">argv</globalname>\endxmlonly .
|
||||
*
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::args">args</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::argv">argv</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct args_
|
||||
{
|
||||
template<typename T>
|
||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||
template<typename T>
|
||||
using value_type = typename remove_reference_t<T>::value_type;
|
||||
|
||||
template<typename T>
|
||||
using vvalue_type = value_type<value_type<T>>;
|
||||
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range));
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, false>(str);
|
||||
// }
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
|
||||
The `args` property allows to explicitly set arguments for the execution. The
|
||||
name of the executable will always be the first element in the arg-vector.
|
||||
|
||||
\section args_details Details
|
||||
|
||||
\subsection args_operations Operations
|
||||
|
||||
\subsubsection args_set_var Setting values
|
||||
|
||||
To set a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args = value;
|
||||
args(value);
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args = {value1, value2};
|
||||
args({value1, value2});
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_set_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
\subsubsection args_append_var Appending values
|
||||
|
||||
To append a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args += value;
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args += {value1, value2};
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_append_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
|
||||
\subsection args_example Example
|
||||
|
||||
The overload form is used when more than one string is passed, from the second one forward.
|
||||
I.e. the following expressions have the same results:
|
||||
|
||||
\code{.cpp}
|
||||
spawn("gcc", "--version");
|
||||
spawn("gcc", args ="--version");
|
||||
spawn("gcc", args+="--version");
|
||||
spawn("gcc", args ={"--version"});
|
||||
spawn("gcc", args+={"--version"});
|
||||
\endcode
|
||||
|
||||
\note A string will be parsed and set in quotes if it has none and contains spaces.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::args_ args{};
|
||||
|
||||
///Alias for \xmlonly <globalname alt="boost::process::args">args</globalname> \endxmlonly .
|
||||
constexpr boost::process::detail::args_ argv{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/args.hpp>")
|
||||
#include <boost/process/v1/args.hpp>
|
||||
|
||||
@@ -1,132 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/** \file boost/process/async.hpp
|
||||
|
||||
The header which provides the basic asynchrounous features.
|
||||
It provides the on_exit property, which allows callbacks when the process exits.
|
||||
It also implements the necessary traits for passing an boost::asio::io_context,
|
||||
which is needed for asynchronous communication.
|
||||
|
||||
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
|
||||
into the boost::process namespace for convenience.
|
||||
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::on_exit">on_exit</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_ASYNC_HPP_
|
||||
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
#include <boost/process/detail/on_exit.hpp>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/io_context_ref.hpp>
|
||||
#include <boost/process/detail/posix/async_in.hpp>
|
||||
#include <boost/process/detail/posix/async_out.hpp>
|
||||
#include <boost/process/detail/posix/on_exit.hpp>
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/io_context_ref.hpp>
|
||||
#include <boost/process/detail/windows/async_in.hpp>
|
||||
#include <boost/process/detail/windows/async_out.hpp>
|
||||
#include <boost/process/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct async_tag;
|
||||
|
||||
template<typename T>
|
||||
struct is_io_context : std::false_type {};
|
||||
template<>
|
||||
struct is_io_context<api::io_context_ref> : std::true_type {};
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup)
|
||||
{
|
||||
auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup);
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
struct async_builder
|
||||
{
|
||||
boost::asio::io_context * ios;
|
||||
|
||||
void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;};
|
||||
|
||||
typedef api::io_context_ref result_type;
|
||||
api::io_context_ref get_initializer() {return api::io_context_ref (*ios);};
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>
|
||||
{
|
||||
typedef async_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using ::boost::asio::buffer;
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** When an io_context is passed, the on_exit property can be used, to be notified
|
||||
when the child process exits.
|
||||
|
||||
|
||||
The following syntax is valid
|
||||
|
||||
\code{.cpp}
|
||||
on_exit=function;
|
||||
on_exit(function);
|
||||
\endcode
|
||||
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
|
||||
`std::future<int>`.
|
||||
|
||||
\par Example
|
||||
|
||||
\code{.cpp}
|
||||
io_context ios;
|
||||
|
||||
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
std::future<int> exit_code;
|
||||
chlid c2("ls", ios, on_exit=exit_code);
|
||||
|
||||
\endcode
|
||||
|
||||
\note The handler is not invoked when the launch fails.
|
||||
\warning When used \ref ignore_error it might get invoked on error.
|
||||
\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the
|
||||
same restrictions as that class (do not register a handler for `SIGCHLD` except by using
|
||||
`boost::asio::signal_set`).
|
||||
*/
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async.hpp>")
|
||||
#include <boost/process/v1/async.hpp>
|
||||
|
||||
@@ -1,217 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
#define BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/async_pipe.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/async_pipe.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
|
||||
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
|
||||
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
|
||||
* boost::asio::posix::stream_descriptor.
|
||||
*
|
||||
* It can be used directly with boost::asio::async_read or async_write.
|
||||
*
|
||||
* \note The object is copyable, but that does invoke a handle duplicate.
|
||||
*/
|
||||
class async_pipe
|
||||
{
|
||||
public:
|
||||
/** Typedef for the native handle representation.
|
||||
* \note This is the handle on the system, not the boost.asio class.
|
||||
*
|
||||
*/
|
||||
typedef platform_specific native_handle_type;
|
||||
/** Typedef for the handle representation of boost.asio.
|
||||
*
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
* Initializes source and sink with the same io_context.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios, const std::string & name);
|
||||
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink, const std::string & name);
|
||||
|
||||
/** Copy-Constructor of the async pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
async_pipe(const async_pipe& lhs);
|
||||
|
||||
/** Move-Constructor of the async pipe.
|
||||
*/
|
||||
async_pipe(async_pipe&& lhs);
|
||||
|
||||
/** Construct the async-pipe from a pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
/** Construct the async-pipe from a pipe, with two different io_context objects.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
|
||||
/** Assign a basic_pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
|
||||
/** Copy Assign a pipe.
|
||||
* @note Duplicates the handles.
|
||||
*/
|
||||
async_pipe& operator=(const async_pipe& lhs);
|
||||
/** Move assign a pipe */
|
||||
async_pipe& operator=(async_pipe&& lhs);
|
||||
|
||||
/** Destructor. Closes the pipe handles. */
|
||||
~async_pipe();
|
||||
|
||||
/** Explicit cast to basic_pipe. */
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
/** Cancel the current asynchronous operations. */
|
||||
void cancel();
|
||||
/** Close the pipe handles. */
|
||||
void close();
|
||||
/** Close the pipe handles. While passing an error_code
|
||||
*
|
||||
*/
|
||||
void close(std::error_code & ec);
|
||||
|
||||
/** Check if the pipes are open. */
|
||||
bool is_open() const;
|
||||
|
||||
/** Async close, i.e. close after current operation is completed.
|
||||
*
|
||||
* \note There is no guarantee that this will indeed read the entire pipe-buffer
|
||||
*/
|
||||
void async_close();
|
||||
|
||||
/** Read some data from the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Write some data to the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Get the native handle of the source. */
|
||||
native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
|
||||
/** Get the native handle of the sink. */
|
||||
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
|
||||
|
||||
/** Start an asynchronous read.
|
||||
*
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
detail::dummy async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler);
|
||||
|
||||
/** Start an asynchronous write.
|
||||
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
|
||||
*/
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
detail::dummy async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler);
|
||||
|
||||
///Get the asio handle of the pipe sink.
|
||||
const handle_type & sink () const &;
|
||||
///Get the asio handle of the pipe source.
|
||||
const handle_type & source() const &;
|
||||
|
||||
///Get the asio handle of the pipe sink. Qualified as rvalue
|
||||
handle_type && sink () &&;
|
||||
///Get the asio handle of the pipe source. Qualified as rvalue
|
||||
handle_type && source() &&;
|
||||
|
||||
/// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move.
|
||||
handle_type source(::boost::asio::io_context& ios) &&;
|
||||
/// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move
|
||||
handle_type sink (::boost::asio::io_context& ios) &&;
|
||||
|
||||
/// Copy the source out of this class and change the io_context. \attention Will always copy.
|
||||
handle_type source(::boost::asio::io_context& ios) const &;
|
||||
/// Copy the sink out of this class and change the io_context. \attention Will always copy
|
||||
handle_type sink (::boost::asio::io_context& ios) const &;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
using ::boost::process::detail::api::async_pipe;
|
||||
#endif
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_pipe.hpp>")
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
|
||||
@@ -1,144 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/async_system.hpp
|
||||
*
|
||||
* Defines the asynchrounous version of the system function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
#define BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/async.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/detail/async_handler.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <tuple>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ExitHandler>
|
||||
struct async_system_handler : ::boost::process::detail::api::async_handler
|
||||
{
|
||||
boost::asio::io_context & ios;
|
||||
boost::asio::async_completion<
|
||||
ExitHandler, void(boost::system::error_code, int)> init;
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
bool errored = false;
|
||||
#endif
|
||||
|
||||
template<typename ExitHandler_>
|
||||
async_system_handler(
|
||||
boost::asio::io_context & ios,
|
||||
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename Exec>
|
||||
void on_error(Exec&, const std::error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
errored = true;
|
||||
#endif
|
||||
auto & h = init.completion_handler;
|
||||
boost::asio::post(
|
||||
ios.get_executor(),
|
||||
[h, ec]() mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
|
||||
});
|
||||
}
|
||||
|
||||
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
get_result()
|
||||
{
|
||||
return init.result.get();
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
if (errored)
|
||||
return [](int , const std::error_code &){};
|
||||
#endif
|
||||
auto & h = init.completion_handler;
|
||||
return [h](int exit_code, const std::error_code & ec) mutable
|
||||
{
|
||||
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ExitHandler>
|
||||
struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
|
||||
|
||||
}
|
||||
|
||||
/** This function provides an asynchronous interface to process launching.
|
||||
|
||||
It uses the same properties and parameters as the other launching function,
|
||||
but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
|
||||
|
||||
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
|
||||
the return value (from the second parameter, `exit_handler`).
|
||||
|
||||
\param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
|
||||
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
|
||||
|
||||
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
|
||||
|
||||
*/
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline boost::process::detail::dummy
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
|
||||
#endif
|
||||
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
|
||||
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
|
||||
{
|
||||
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
|
||||
|
||||
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
|
||||
has_err_handling;
|
||||
|
||||
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
|
||||
|
||||
|
||||
child(ios, std::forward<Args>(args)..., async_h ).detach();
|
||||
|
||||
return async_h.get_result();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/async_system.hpp>")
|
||||
#include <boost/process/v1/async_system.hpp>
|
||||
|
||||
@@ -1,154 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/child.hpp
|
||||
*
|
||||
* Defines a child process class.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_CHILD_HPP
|
||||
#define BOOST_PROCESS_CHILD_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
///The main namespace of boost.process.
|
||||
namespace process {
|
||||
|
||||
template<typename ...Args>
|
||||
child::child(Args&&...args)
|
||||
: child(::boost::process::detail::execute_impl(std::forward<Args>(args)...)) {}
|
||||
|
||||
|
||||
///Typedef for the type of an pid_t
|
||||
typedef ::boost::process::detail::api::pid_t pid_t;
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
|
||||
* in that it has a join and detach function.
|
||||
*
|
||||
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
|
||||
*
|
||||
*/
|
||||
|
||||
class child
|
||||
{
|
||||
/** Type definition for the native process handle. */
|
||||
typedef platform_specific native_handle_t;
|
||||
|
||||
/** Construct the child from a pid.
|
||||
*
|
||||
* @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific.
|
||||
*/
|
||||
explicit child(pid_t & pid) : _child_handle(pid) {};
|
||||
|
||||
/** Move-Constructor.*/
|
||||
child(child && lhs);
|
||||
|
||||
/** Construct a child from a property list and launch it
|
||||
* The standard version is to create a subprocess, which will spawn the process.
|
||||
*/
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
|
||||
/** Construct an empty child. */
|
||||
child() = default;
|
||||
|
||||
/** Move assign. */
|
||||
child& operator=(child && lhs);
|
||||
|
||||
/** Detach the child, i.e. let it run after this handle dies. */
|
||||
void detach();
|
||||
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
|
||||
void join();
|
||||
/** Check if the child is joinable. */
|
||||
bool joinable();
|
||||
|
||||
/** Destructor.
|
||||
* @attention Will call terminate (without warning) when the child was neither joined nor detached.
|
||||
*/
|
||||
~child();
|
||||
|
||||
/** Get the native handle for the child process. */
|
||||
native_handle_t native_handle() const;
|
||||
|
||||
/** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */
|
||||
int exit_code() const;
|
||||
/** Get the Process Identifier. */
|
||||
pid_t id() const;
|
||||
|
||||
/** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited
|
||||
* for or if it was terminated. */
|
||||
int native_exit_code() const;
|
||||
|
||||
/** Check if the child process is running. */
|
||||
bool running();
|
||||
/** \overload void running() */
|
||||
bool running(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit. */
|
||||
void wait();
|
||||
/** \overload void wait() */
|
||||
void wait(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit for a period of time.
|
||||
* \return True if child exited while waiting.
|
||||
*/
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit until a point in time.
|
||||
* \return True if child exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Check if this handle holds a child process.
|
||||
* @note That does not mean, that the process is still running. It only means, that the handle does or did exist.
|
||||
*/
|
||||
bool valid() const;
|
||||
/** Same as valid, for convenience. */
|
||||
explicit operator bool() const;
|
||||
|
||||
/** Check if the the chlid process is in any process group. */
|
||||
bool in_group() const;
|
||||
|
||||
/** \overload bool in_group() const */
|
||||
bool in_group(std::error_code & ec) const noexcept;
|
||||
|
||||
/** Terminate the child process.
|
||||
*
|
||||
* This function will cause the child process to unconditionally and immediately exit.
|
||||
* It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix
|
||||
* and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows.
|
||||
*
|
||||
*/
|
||||
void terminate();
|
||||
|
||||
/** \overload void terminate() */
|
||||
void terminate(std::error_code & ec) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/child.hpp>")
|
||||
#include <boost/process/v1/child.hpp>
|
||||
|
||||
@@ -1,122 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
|
||||
#include <boost/winapi/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/cmd.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/cmd.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::cmd">cmd</globalname>\endxmlonly property.
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::cmd">cmd</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() = default;
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const Char *s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const Char *s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, api::cmd_setter_<wchar_t>>
|
||||
{
|
||||
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
|
||||
{
|
||||
return { ::boost::process::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, api::cmd_setter_<char>>
|
||||
{
|
||||
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
|
||||
{
|
||||
return { ::boost::process::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The cmd property allows to explicitly set commands for the execution.
|
||||
|
||||
The overload form applies when only one string is passed to a launching function.
|
||||
The string will be internally parsed and split at spaces.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t`.
|
||||
|
||||
\code{.cpp}
|
||||
cmd="value";
|
||||
cmd(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::detail::cmd_ cmd;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/cmd.hpp>")
|
||||
#include <boost/process/v1/cmd.hpp>
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <system_error>
|
||||
#include <functional>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
|
||||
struct on_exit_ : boost::process::detail::posix::async_handler
|
||||
{
|
||||
std::function<void(int, const std::error_code&)> handler;
|
||||
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
return handler;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
#endif /* BOOST_PROCESS_POSIX_ON_EXIT_HPP_ */
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_TRAITS_HPP_
|
||||
#define BOOST_PROCESS_TRAITS_HPP_
|
||||
|
||||
#include <boost/process/detail/traits/decl.hpp>
|
||||
#include <boost/process/detail/traits/async.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/env.hpp>
|
||||
#include <boost/process/detail/traits/error.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#endif /* BOOST_PROCESS_TRAITS_HPP_ */
|
||||
@@ -1,502 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ENV_HPP_
|
||||
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/none.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/env_init.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/env_init.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/env.hpp
|
||||
*
|
||||
* This header which provides the `env` property. It allows the modification of the
|
||||
* environment the child process will run in, in a functional style.
|
||||
*
|
||||
* \xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::env">env</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
* \endxmlonly
|
||||
*
|
||||
* For additional information see the platform documentations:
|
||||
*
|
||||
* - [windows](https://msdn.microsoft.com/en-US/library/windows/desktop/ms682653.aspx)
|
||||
* - [posix](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const std::basic_string<Char> & ch)
|
||||
{
|
||||
return ch.size() + 1;
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
std::size_t make_env_string_size(const Char * ch)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
while (ch[sz] != null_char<Char>())
|
||||
sz++;
|
||||
|
||||
sz++;
|
||||
return sz;
|
||||
}
|
||||
|
||||
template<typename Char, typename Container>
|
||||
inline std::basic_string<Char> make_env_string(const Container & value)
|
||||
{
|
||||
std::size_t sz = 0;
|
||||
for (auto & v : value)
|
||||
sz += make_env_string_size(v);
|
||||
|
||||
std::basic_string<Char> s;
|
||||
s.reserve(sz); //+1 for ;, end doesn't have one.
|
||||
|
||||
for (auto & val : value)
|
||||
(s += val) += api::env_seperator<Char>();
|
||||
|
||||
s.resize(s.size() -1); //remove last ';'
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_set
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_append
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
string_type value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_reset
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
};
|
||||
|
||||
|
||||
template<> struct is_wchar_t<env_set<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_append<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<env_reset<wchar_t>> : std::true_type {};
|
||||
template<> struct is_wchar_t<basic_environment<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_set<wchar_t>>
|
||||
{
|
||||
static env_set<char> conv(const env_set<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_set<char>>
|
||||
{
|
||||
static env_set<wchar_t> conv(const env_set<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_append<wchar_t>>
|
||||
{
|
||||
static env_append<char> conv(const env_append<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_append<char>>
|
||||
{
|
||||
static env_append<wchar_t> conv(const env_append<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key),
|
||||
::boost::process::detail::convert(in.value)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_reset<wchar_t>>
|
||||
{
|
||||
static env_reset<char> conv(const env_reset<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_reset<char>>
|
||||
{
|
||||
static env_reset<wchar_t> conv(const env_reset<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.key)};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Char>
|
||||
struct env_init
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, env_init<wchar_t>>
|
||||
{
|
||||
static env_init<char> conv(const env_init<wchar_t> & in)
|
||||
{
|
||||
return {basic_environment<char>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, env_init<char>>
|
||||
{
|
||||
static env_init<wchar_t> conv(const env_init<char> & in)
|
||||
{
|
||||
return {basic_environment<wchar_t>(in.env)};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, basic_environment<wchar_t>>
|
||||
{
|
||||
static basic_environment<char> conv(const basic_environment<wchar_t> & in)
|
||||
{
|
||||
return { basic_environment<char>(in) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, basic_environment<char>>
|
||||
{
|
||||
static basic_environment<wchar_t> conv(const basic_environment<char> & in)
|
||||
{
|
||||
return { basic_environment<wchar_t>(in) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_proxy
|
||||
{
|
||||
using string_type = std::basic_string<Char>;
|
||||
string_type key;
|
||||
|
||||
|
||||
env_set<Char> operator=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
}
|
||||
env_set<Char> operator=(const std::vector<string_type> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_set<Char> operator=(const std::initializer_list<const Char*> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
|
||||
env_append<Char> operator+=(const string_type & value)
|
||||
{
|
||||
return {std::move(key), value};
|
||||
}
|
||||
env_append<Char> operator+=(const std::vector<string_type> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_append<Char> operator+=(const std::initializer_list<const Char*> & value)
|
||||
{
|
||||
return {std::move(key), make_env_string<Char>(value)};
|
||||
}
|
||||
env_reset<Char> operator=(boost::none_t)
|
||||
{
|
||||
return {std::move(key)};
|
||||
}
|
||||
};
|
||||
|
||||
struct env_
|
||||
{
|
||||
constexpr env_() {};
|
||||
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::basic_string<Char> & value) const
|
||||
{
|
||||
return {key, value};
|
||||
}
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::vector<std::basic_string<Char>> & value) const
|
||||
{
|
||||
return {key, make_env_string<Char>(value)};
|
||||
}
|
||||
template<typename Char>
|
||||
env_set<Char> operator()(const std::basic_string<Char> & key,
|
||||
const std::initializer_list<Char*> & value) const
|
||||
{
|
||||
return {key, make_env_string<Char>(value)};
|
||||
}
|
||||
template<typename Char>
|
||||
env_reset<Char> operator()(const std::basic_string<Char> & key, boost::none_t)
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_proxy<Char> operator[](const std::basic_string<Char> & key) const
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_proxy<Char> operator[](const Char* key) const
|
||||
{
|
||||
return {key};
|
||||
}
|
||||
template<typename Char>
|
||||
env_init<Char> operator()(const basic_environment<Char> & env) const
|
||||
{
|
||||
return {env};
|
||||
}
|
||||
template<typename Char>
|
||||
env_init<Char> operator= (const basic_environment<Char> & env) const
|
||||
{
|
||||
return {env};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct env_builder
|
||||
{
|
||||
basic_environment<Char> env;
|
||||
env_builder() : env{basic_native_environment<Char>()} {}
|
||||
|
||||
void operator()(const basic_environment<Char> & e)
|
||||
{
|
||||
env = e;
|
||||
}
|
||||
|
||||
void operator()(env_init<Char> & ei)
|
||||
{
|
||||
env = std::move(ei.env);
|
||||
}
|
||||
void operator()(env_set<Char> & es)
|
||||
{
|
||||
env[es.key] = es.value;
|
||||
}
|
||||
void operator()(env_reset<Char> & es)
|
||||
{
|
||||
env.erase(es.key);
|
||||
}
|
||||
template<typename T>
|
||||
void operator()(env_append<T> & es)
|
||||
{
|
||||
env[es.key] += es.value;
|
||||
}
|
||||
|
||||
typedef api::env_init<Char> result_type;
|
||||
api::env_init<Char> get_initializer()
|
||||
{
|
||||
return api::env_init<Char>(std::move(env));
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<char>>
|
||||
{
|
||||
typedef env_builder<char> type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<env_tag<wchar_t>>
|
||||
{
|
||||
typedef env_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
The `env` property provides a functional way to modify the environment used by
|
||||
the child process. If none is passed the environment is inherited from the father
|
||||
process. Appending means that the environment will be interpreted as a ';' or ':'
|
||||
separated list as used in `PATH`.
|
||||
|
||||
On both `posix` and `windows` the environment variables can be lists of strings,
|
||||
separated by ';'. This is typically used for the `PATH` variable.
|
||||
|
||||
By default the environment will be inherited from the launching process,
|
||||
which is also true if environment are modified with this initializer.
|
||||
|
||||
\section env_details Details
|
||||
|
||||
\subsection env_operations Operations
|
||||
|
||||
\subsubsection env_set_var Setting variables
|
||||
|
||||
To set a variable `id` the value `value` the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = value;
|
||||
env(id, value);
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = {value1, value2};
|
||||
env(id, {value1, value2});
|
||||
\endcode
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
\paragraph id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_set_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
\note Using `std::vector` or `std::initializer_list`
|
||||
|
||||
\subsubsection env_append_var Append variables
|
||||
|
||||
Appending means, that a variable will be interpreted as a
|
||||
To append a variable `id` the value `value` the following syntax can be used:
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += value;
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
env[id] += {value1, value2};
|
||||
\endcode
|
||||
|
||||
\note Creates the variable if it does not exist.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`
|
||||
for both `id` and `value`.
|
||||
|
||||
\paragraph env_append_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_append_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
|
||||
\subsubsection env_reset Reset variables
|
||||
|
||||
Reseting signle variables can be done in the following way:
|
||||
|
||||
\code{.cpp}
|
||||
env[id] = boost::none;
|
||||
env(id, boost::none);
|
||||
\endcode
|
||||
|
||||
\note This does not set the value empty, but removes it from the list.
|
||||
|
||||
The following lists contain possible value types, with `char_type` being either `char` or `wchar_t`:
|
||||
|
||||
\paragraph env_reset_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\subsubsection env_init Initialize the environment
|
||||
|
||||
The whole environment can be initialized from an object of type
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
|
||||
\code{.cpp}
|
||||
env=env;
|
||||
env(env);
|
||||
\endcode
|
||||
|
||||
\note The passed `environment` can also be default-constructed to get an empty environment.
|
||||
|
||||
\paragraph env_init_var_id id
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type *`
|
||||
|
||||
\paragraph env_init_var_value value
|
||||
|
||||
- `boost::process::basic_environment<char_type>`
|
||||
|
||||
\subsection env_example Example
|
||||
|
||||
\code{.cpp}
|
||||
spawn("b2", env["PATH"]+="F:/boost", env["SOME_VAR"]=boost::none, env["NEW_VAR"]="VALUE");
|
||||
\endcode
|
||||
|
||||
If the overload style should be done by passing an instance of
|
||||
\xmlonly <classname>boost::process::environment</classname> \endxmlonly
|
||||
the above example would look like this.
|
||||
|
||||
\code{.cpp}
|
||||
environment e = this_process::environment();
|
||||
e["PATH"] += "F:/boost";
|
||||
e.erase("SOME_VAR");
|
||||
e["NEW_VAR"] = "VALUE";
|
||||
spawn("b2", e);
|
||||
\endcode
|
||||
|
||||
\warning Passing an empty environment will cause undefined behaviour.
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::env_ env{};
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENV_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/env.hpp>")
|
||||
#include <boost/process/v1/env.hpp>
|
||||
|
||||
@@ -1,705 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_ENVIRONMENT_HPP_
|
||||
#define BOOST_PROCESS_ENVIRONMENT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/iterator/transform_iterator.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/environment.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/environment.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry
|
||||
{
|
||||
using value_type = Char ;
|
||||
using pointer = const value_type * ;
|
||||
using string_type = std::basic_string<value_type> ;
|
||||
using range = boost::iterator_range<pointer> ;
|
||||
using environment_t = Environment ;
|
||||
|
||||
std::vector<string_type> to_vector() const
|
||||
{
|
||||
if (_data == nullptr)
|
||||
return std::vector<string_type>();
|
||||
std::vector<string_type> data;
|
||||
auto str = string_type(_data);
|
||||
struct splitter
|
||||
{
|
||||
bool operator()(wchar_t w) const {return w == api::env_seperator<wchar_t>();}
|
||||
bool operator()(char c) const {return c == api::env_seperator<char> ();}
|
||||
} s;
|
||||
boost::split(data, _data, s);
|
||||
return data;
|
||||
}
|
||||
string_type to_string() const
|
||||
{
|
||||
if (_data != nullptr)
|
||||
return string_type(_data);
|
||||
else
|
||||
return string_type();
|
||||
}
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
explicit const_entry(string_type&& name, pointer data, environment_t & env_) :
|
||||
_name(std::move(name)), _data(data), _env(&env_) {}
|
||||
|
||||
explicit const_entry(string_type &&name, environment_t & env) :
|
||||
_name(std::move(name)), _data(nullptr), _env(&env) {}
|
||||
const_entry(const const_entry&) = default;
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
|
||||
void reload()
|
||||
{
|
||||
auto p = _env->find(_name);
|
||||
if (p == _env->end())
|
||||
_data = nullptr;
|
||||
else
|
||||
_data = p->_data;
|
||||
this->_env->reload();
|
||||
|
||||
}
|
||||
bool empty() const
|
||||
{
|
||||
return _data == nullptr;
|
||||
}
|
||||
protected:
|
||||
string_type _name;
|
||||
pointer _data;
|
||||
environment_t * _env;
|
||||
};
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct entry : const_entry<Char, Environment>
|
||||
{
|
||||
using father = const_entry<Char, Environment>;
|
||||
using value_type = typename father::value_type;
|
||||
using string_type = typename father::string_type;
|
||||
using pointer = typename father::pointer;
|
||||
using environment_t = typename father::environment_t;
|
||||
|
||||
explicit entry(string_type&& name, pointer data, environment_t & env) :
|
||||
father(std::move(name), data, env) {}
|
||||
|
||||
explicit entry(string_type &&name, environment_t & env_) :
|
||||
father(std::move(name), env_) {}
|
||||
|
||||
entry(const entry&) = default;
|
||||
entry& operator=(const entry&) = default;
|
||||
|
||||
void assign(const string_type &value)
|
||||
{
|
||||
this->_env->set(this->_name, value);
|
||||
this->reload();
|
||||
}
|
||||
void assign(const std::vector<string_type> &value)
|
||||
{
|
||||
string_type data;
|
||||
for (auto &v : value)
|
||||
{
|
||||
if (&v != &value.front())
|
||||
data += api::env_seperator<value_type>();
|
||||
data += v;
|
||||
}
|
||||
this->_env->set(this->_name, data);
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void assign(const std::initializer_list<string_type> &value)
|
||||
{
|
||||
string_type data;
|
||||
for (auto &v : value)
|
||||
{
|
||||
if (&v != &*value.begin())
|
||||
data += api::env_seperator<value_type>();
|
||||
data += v;
|
||||
}
|
||||
this->_env->set(this->_name, data);
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void append(const string_type &value)
|
||||
{
|
||||
if (this->_data == nullptr)
|
||||
this->_env->set(this->_name, value);
|
||||
else
|
||||
{
|
||||
string_type st = this->_data;
|
||||
this->_env->set(this->_name, st + api::env_seperator<value_type>() + value);
|
||||
}
|
||||
|
||||
|
||||
this->reload();
|
||||
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
this->_env->reset(this->_name);
|
||||
this->_env->reload();
|
||||
this->_data = nullptr;
|
||||
}
|
||||
entry &operator=(const string_type & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator=(const std::vector<string_type> & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator=(const std::initializer_list<string_type> & value)
|
||||
{
|
||||
assign(value);
|
||||
return *this;
|
||||
}
|
||||
entry &operator+=(const string_type & value)
|
||||
{
|
||||
append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct make_entry
|
||||
{
|
||||
|
||||
make_entry(const make_entry&) = default;
|
||||
make_entry& operator=(const make_entry&) = default;
|
||||
|
||||
Environment *env;
|
||||
make_entry(Environment & env) : env(&env) {};
|
||||
entry<Char, Environment> operator()(const Char* data) const
|
||||
{
|
||||
auto p = data;
|
||||
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
|
||||
p++;
|
||||
auto name = std::basic_string<Char>(data, p);
|
||||
p++; //go behind equal sign
|
||||
|
||||
return entry<Char, Environment>(std::move(name), p, *env);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Char, typename Environment>
|
||||
struct make_const_entry
|
||||
{
|
||||
|
||||
make_const_entry(const make_const_entry&) = default;
|
||||
make_const_entry& operator=(const make_const_entry&) = default;
|
||||
|
||||
Environment *env;
|
||||
make_const_entry(Environment & env) : env(&env) {};
|
||||
const_entry<Char, Environment> operator()(const Char* data) const
|
||||
{
|
||||
auto p = data;
|
||||
while ((*p != equal_sign<Char>()) && (*p != null_char<Char>()))
|
||||
p++;
|
||||
auto name = std::basic_string<Char>(data, p);
|
||||
p++; //go behind equal sign
|
||||
|
||||
return const_entry<Char, Environment>(std::move(name), p, *env);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#if !defined (BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
template<typename Char, template <class> class Implementation = detail::api::basic_environment_impl>
|
||||
class basic_environment_impl : public Implementation<Char>
|
||||
{
|
||||
Char** _get_end() const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
while (*p != nullptr)
|
||||
p++;
|
||||
|
||||
return p;
|
||||
}
|
||||
public:
|
||||
using string_type = std::basic_string<Char>;
|
||||
using implementation_type = Implementation<Char>;
|
||||
using base_type = basic_environment_impl<Char, Implementation>;
|
||||
using entry_maker = detail::make_entry<Char, base_type>;
|
||||
using entry_type = detail::entry <Char, base_type>;
|
||||
using const_entry_type = detail::const_entry <Char, const base_type>;
|
||||
using const_entry_maker = detail::make_const_entry<Char, const base_type>;
|
||||
|
||||
friend entry_type;
|
||||
friend const_entry_type;
|
||||
|
||||
using iterator = boost::transform_iterator< entry_maker, Char**, entry_type, entry_type>;
|
||||
using const_iterator = boost::transform_iterator<const_entry_maker, Char**, const_entry_type, const_entry_type>;
|
||||
using size_type = std::size_t;
|
||||
|
||||
iterator begin() {return iterator(this->_env_impl, entry_maker(*this));}
|
||||
const_iterator begin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
|
||||
const_iterator cbegin() const {return const_iterator(this->_env_impl, const_entry_maker(*this));}
|
||||
|
||||
iterator end() {return iterator(_get_end(), entry_maker(*this));}
|
||||
const_iterator end() const {return const_iterator(_get_end(), const_entry_maker(*this));}
|
||||
const_iterator cend() const {return const_iterator(_get_end(), const_entry_maker(*this));}
|
||||
|
||||
iterator find( const string_type& key )
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
return iterator(p, entry_maker(*this));
|
||||
}
|
||||
const_iterator find( const string_type& key ) const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
return const_iterator(p, const_entry_maker(*this));
|
||||
}
|
||||
|
||||
std::size_t count(const string_type & st) const
|
||||
{
|
||||
auto p = this->_env_impl;
|
||||
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
|
||||
while (*p != nullptr)
|
||||
{
|
||||
if (std::equal(st1.begin(), st1.end(), *p))
|
||||
return 1u;
|
||||
p++;
|
||||
}
|
||||
return 0u;
|
||||
}
|
||||
void erase(const string_type & id)
|
||||
{
|
||||
implementation_type::reset(id);
|
||||
this->reload();
|
||||
}
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value)
|
||||
{
|
||||
auto f = find(id);
|
||||
if (f == end())
|
||||
{
|
||||
implementation_type::set(id, value);
|
||||
this->reload();
|
||||
return std::pair<iterator, bool>(find(id), true);
|
||||
}
|
||||
else
|
||||
return std::pair<iterator, bool>(f, false);
|
||||
}
|
||||
using implementation_type::implementation_type;
|
||||
using implementation_type::operator=;
|
||||
using native_handle_type = typename implementation_type::native_handle_type;
|
||||
using implementation_type::native_handle;
|
||||
//copy ctor if impl is copy-constructible
|
||||
bool empty()
|
||||
{
|
||||
return *this->_env_impl == nullptr;
|
||||
}
|
||||
std::size_t size() const
|
||||
{
|
||||
return (_get_end() - this->_env_impl);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
std::vector<string_type> names;
|
||||
names.resize(size());
|
||||
std::transform(cbegin(), cend(), names.begin(), [](const const_entry_type & cet){return cet.get_name();});
|
||||
|
||||
for (auto & nm : names)
|
||||
implementation_type::reset(nm);
|
||||
|
||||
this->reload();
|
||||
}
|
||||
|
||||
entry_type at( const string_type& key )
|
||||
{
|
||||
auto f = find(key);
|
||||
if (f== end())
|
||||
throw std::out_of_range(key + " not found");
|
||||
return *f;
|
||||
}
|
||||
const_entry_type at( const string_type& key ) const
|
||||
{
|
||||
auto f = find(key);
|
||||
if (f== end())
|
||||
throw std::out_of_range(key + " not found");
|
||||
return *f;
|
||||
}
|
||||
entry_type operator[](const string_type & key)
|
||||
{
|
||||
auto p = find(key);
|
||||
if (p != end())
|
||||
return *p;
|
||||
|
||||
return entry_type(string_type(key), *this);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/**Template representation of environments. It takes a character type (`char` or `wchar_t`)
|
||||
* as template parameter to implement the environment
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_environment
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::basic_string<Char> string_type;
|
||||
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
|
||||
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
|
||||
typedef std::size_t size_type ;
|
||||
|
||||
iterator begin() ; ///<Returns an iterator to the beginning
|
||||
const_iterator begin() const ; ///<Returns an iterator to the beginning
|
||||
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
|
||||
|
||||
iterator end() ; ///<Returns an iterator to the end
|
||||
const_iterator end() const; ///<Returns an iterator to the end
|
||||
const_iterator cend() const; ///<Returns an iterator to the end
|
||||
|
||||
iterator find( const string_type& key ); ///<Find a variable by its name
|
||||
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
|
||||
|
||||
std::size_t count(const string_type & st) const; ///<Number of variables
|
||||
void erase(const string_type & id); ///<Erase variable by id.
|
||||
///Emplace an environment variable.
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
|
||||
|
||||
///Default constructor
|
||||
basic_environment();
|
||||
///Copy constructor.
|
||||
basic_environment(const basic_environment & );
|
||||
///Move constructor.
|
||||
basic_environment(basic_environment && );
|
||||
|
||||
///Copy assignment.
|
||||
basic_environment& operator=(const basic_environment & );
|
||||
///Move assignment.
|
||||
basic_environment& operator=(basic_environment && );
|
||||
|
||||
typedef typename detail::implementation_type::native_handle_type native_handle;
|
||||
|
||||
///Check if environment has entries.
|
||||
bool empty();
|
||||
///Get the number of variables.
|
||||
std::size_t size() const;
|
||||
///Clear the environment. @attention Use with care, passed environment cannot be empty.
|
||||
void clear();
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
entry_type at( const string_type& key );
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
const_entry_type at( const string_type& key ) const;
|
||||
///Get the entry with the given key. It creates the entry if it doesn't exist.
|
||||
entry_type operator[](const string_type & key);
|
||||
|
||||
/**Proxy class used for read access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry_type
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
const_entry(const const_entry&) = default;
|
||||
///Move Constructor
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/**Proxy class used for read and write access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct entry_type
|
||||
{
|
||||
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
entry(const entry&) = default;
|
||||
///Move Constructor
|
||||
entry& operator=(const entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
|
||||
///Assign a string to the value
|
||||
void assign(const string_type &value);
|
||||
///Assign a set of strings to the entry; they will be separated by ';' or ':'.
|
||||
void assign(const std::vector<string_type> &value);
|
||||
///Append a string to the end of the entry, it will separated by ';' or ':'.
|
||||
void append(const string_type &value);
|
||||
///Reset the value
|
||||
void clear();
|
||||
///Assign a string to the entry.
|
||||
entry &operator=(const string_type & value);
|
||||
///Assign a set of strings to the entry; they will be separated by ';' or ':'.
|
||||
entry &operator=(const std::vector<string_type> & value);
|
||||
///Append a string to the end of the entry, it will separated by ';' or ':'.
|
||||
entry &operator+=(const string_type & value);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**Template representation of the environment of this process. It takes a template
|
||||
* as template parameter to implement the environment. All instances of this class
|
||||
* refer to the same environment, but might not get updated if another one makes changes.
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_native_environment
|
||||
{
|
||||
|
||||
public:
|
||||
typedef std::basic_string<Char> string_type;
|
||||
typedef boost::transform_iterator< entry_maker, Char**> iterator ;
|
||||
typedef boost::transform_iterator<const_entry_maker, Char**> const_iterator ;
|
||||
typedef std::size_t size_type ;
|
||||
|
||||
iterator begin() ; ///<Returns an iterator to the beginning
|
||||
const_iterator begin() const ; ///<Returns an iterator to the beginning
|
||||
const_iterator cbegin() const ; ///<Returns an iterator to the beginning
|
||||
|
||||
iterator end() ; ///<Returns an iterator to the end
|
||||
const_iterator end() const; ///<Returns an iterator to the end
|
||||
const_iterator cend() const; ///<Returns an iterator to the end
|
||||
|
||||
iterator find( const string_type& key ); ///<Find a variable by its name
|
||||
const_iterator find( const string_type& key ) const; ///<Find a variable by its name
|
||||
|
||||
std::size_t count(const string_type & st) const; ///<Number of variables
|
||||
void erase(const string_type & id); ///<Erase variable by id.
|
||||
///Emplace an environment variable.
|
||||
std::pair<iterator,bool> emplace(const string_type & id, const string_type & value);
|
||||
|
||||
///Default constructor
|
||||
basic_native_environment();
|
||||
///Move constructor.
|
||||
basic_native_environment(basic_native_environment && );
|
||||
///Move assignment.
|
||||
basic_native_environment& operator=(basic_native_environment && );
|
||||
|
||||
typedef typename detail::implementation_type::native_handle_type native_handle;
|
||||
|
||||
///Check if environment has entries.
|
||||
bool empty();
|
||||
///Get the number of variables.
|
||||
std::size_t size() const;
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
entry_type at( const string_type& key );
|
||||
///Get the entry with the key. Throws if it does not exist.
|
||||
const_entry_type at( const string_type& key ) const;
|
||||
///Get the entry with the given key. It creates the entry if it doesn't exist.
|
||||
entry_type operator[](const string_type & key);
|
||||
|
||||
/**Proxy class used for read access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct const_entry_type
|
||||
{
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
const_entry(const const_entry&) = default;
|
||||
///Move Constructor
|
||||
const_entry& operator=(const const_entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/**Proxy class used for read and write access to members by [] or .at()
|
||||
* @attention Holds a reference to the environment it was created from.
|
||||
*/
|
||||
template<typename Char, typename Environment>
|
||||
struct entry_type
|
||||
{
|
||||
|
||||
typedef Char value_type;
|
||||
typedef const value_type * pointer;
|
||||
typedef std::basic_string<value_type> string_type;
|
||||
typedef boost::iterator_range<pointer> range;
|
||||
typedef Environment environment_t;
|
||||
|
||||
///Split the entry by ";" or ":" and return it as a vector. Used by PATH.
|
||||
std::vector<string_type> to_vector() const
|
||||
///Get the value as string.
|
||||
string_type to_string() const
|
||||
///Get the name of this entry.
|
||||
string_type get_name() const {return string_type(_name.begin(), _name.end());}
|
||||
///Copy Constructor
|
||||
entry(const entry&) = default;
|
||||
///Move Constructor
|
||||
entry& operator=(const entry&) = default;
|
||||
///Check if the entry is empty.
|
||||
bool empty() const;
|
||||
|
||||
///Assign a string to the value
|
||||
void assign(const string_type &value);
|
||||
///Assign a set of strings to the entry; they will be separated by ';' or ':'.
|
||||
void assign(const std::vector<string_type> &value);
|
||||
///Append a string to the end of the entry, it will separated by ';' or ':'.
|
||||
void append(const string_type &value);
|
||||
///Reset the value
|
||||
void clear();
|
||||
///Assign a string to the entry.
|
||||
entry &operator=(const string_type & value);
|
||||
///Assign a set of strings to the entry; they will be separated by ';' or ':'.
|
||||
entry &operator=(const std::vector<string_type> & value);
|
||||
///Append a string to the end of the entry, it will separated by ';' or ':'.
|
||||
entry &operator+=(const string_type & value);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
///Definition of the environment for the current process.
|
||||
template<typename Char>
|
||||
class basic_native_environment : public basic_environment_impl<Char, detail::api::native_environment_impl>
|
||||
{
|
||||
public:
|
||||
using base_type = basic_environment_impl<Char, detail::api::native_environment_impl>;
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
|
||||
///Type definition to hold a seperate environment.
|
||||
template<typename Char>
|
||||
class basic_environment : public basic_environment_impl<Char, detail::api::basic_environment_impl>
|
||||
{
|
||||
public:
|
||||
using base_type = basic_environment_impl<Char, detail::api::basic_environment_impl>;
|
||||
using base_type::base_type;
|
||||
using base_type::operator=;
|
||||
};
|
||||
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<char> native_environment;
|
||||
#endif
|
||||
///Definition of the environment for the current process.
|
||||
typedef basic_native_environment<wchar_t> wnative_environment;
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<char> environment;
|
||||
#endif
|
||||
///Type definition to hold a seperate environment.
|
||||
typedef basic_environment<wchar_t> wenvironment;
|
||||
|
||||
}
|
||||
|
||||
///Namespace containing information of the calling process.
|
||||
namespace this_process
|
||||
{
|
||||
|
||||
///Definition of the native handle type.
|
||||
typedef ::boost::process::detail::api::native_handle_t native_handle_type;
|
||||
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::native_environment;
|
||||
#endif
|
||||
///Definition of the environment for this process.
|
||||
using ::boost::process::wnative_environment;
|
||||
|
||||
///Get the process id of the current process.
|
||||
inline int get_id() { return ::boost::process::detail::api::get_id();}
|
||||
///Get the native handle of the current process.
|
||||
inline native_handle_type native_handle() { return ::boost::process::detail::api::native_handle();}
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
///Get the enviroment of the current process.
|
||||
inline native_environment environment() { return ::boost::process:: native_environment(); }
|
||||
#endif
|
||||
///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()
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const ::boost::process::wnative_environment ne{};
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
static constexpr auto id = L"PATH";
|
||||
#else
|
||||
const ::boost::process::native_environment ne{};
|
||||
typedef typename ::boost::process::native_environment::const_entry_type value_type;
|
||||
static constexpr auto id = "PATH";
|
||||
#endif
|
||||
|
||||
auto itr = std::find_if(ne.cbegin(), ne.cend(),
|
||||
[&](const value_type & e)
|
||||
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
|
||||
|
||||
if (itr == ne.cend())
|
||||
return {};
|
||||
|
||||
auto vec = itr->to_vector();
|
||||
|
||||
std::vector<boost::filesystem::path> val;
|
||||
val.resize(vec.size());
|
||||
|
||||
std::copy(vec.begin(), vec.end(), val.begin());
|
||||
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ENVIRONMENT_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/environment.hpp>")
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
@@ -1,211 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_ERROR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_ERROR_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/algorithm/query/find_if.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/begin.hpp>
|
||||
#include <boost/fusion/sequence/intrinsic/end.hpp>
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
#include <boost/fusion/sequence/comparison/equal_to.hpp>
|
||||
#include <boost/fusion/container/set/convert.hpp>
|
||||
#include <boost/type_index.hpp>
|
||||
|
||||
/** \file boost/process/error.hpp
|
||||
*
|
||||
* Header which provides the error properties. It allows to explicitly set the error handling, the properties are:
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::ignore_error">ignore_error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::throw_on_error">throw_on_error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error">error</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error_ref">error_ref</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::error_code">error_code</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
* For error there are two aliases: error_ref and error_code
|
||||
*/
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr throw_on_error_() = default;
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const
|
||||
{
|
||||
throw process_error(ec, "process creation failed");
|
||||
}
|
||||
|
||||
const throw_on_error_ &operator()() const {return *this;}
|
||||
};
|
||||
|
||||
struct ignore_error_ : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
constexpr ignore_error_() = default;
|
||||
};
|
||||
|
||||
struct set_on_error : ::boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
set_on_error(const set_on_error&) = default;
|
||||
explicit set_on_error(std::error_code &ec) : ec_(ec) {}
|
||||
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code & ec) const noexcept
|
||||
{
|
||||
ec_ = ec;
|
||||
}
|
||||
|
||||
private:
|
||||
std::error_code &ec_;
|
||||
};
|
||||
|
||||
struct 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);}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_error_handler : std::false_type {};
|
||||
|
||||
template<> struct is_error_handler<set_on_error> : std::true_type {};
|
||||
template<> struct is_error_handler<throw_on_error_> : std::true_type {};
|
||||
template<> struct is_error_handler<ignore_error_> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
template<typename Iterator, typename End>
|
||||
struct has_error_handler_impl
|
||||
{
|
||||
typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
|
||||
typedef typename std::remove_reference<ref_type>::type res_type_;
|
||||
typedef typename std::remove_cv<res_type_>::type res_type;
|
||||
typedef typename is_error_handler<res_type>::type cond;
|
||||
|
||||
typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
|
||||
typedef typename has_error_handler_impl<next_itr, End>::type next;
|
||||
|
||||
typedef typename boost::mpl::or_<cond, next>::type type;
|
||||
};
|
||||
|
||||
template<typename Iterator>
|
||||
struct has_error_handler_impl<Iterator, Iterator>
|
||||
{
|
||||
typedef boost::mpl::false_ type;
|
||||
};
|
||||
|
||||
|
||||
template<typename Sequence>
|
||||
struct has_error_handler
|
||||
{
|
||||
typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type;
|
||||
|
||||
typedef typename has_error_handler_impl<
|
||||
typename boost::fusion::result_of::begin<vector_type>::type,
|
||||
typename boost::fusion::result_of::end< vector_type>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<typename Sequence>
|
||||
struct has_ignore_error
|
||||
{
|
||||
typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_>::type type1;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2;
|
||||
typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3;
|
||||
typedef typename boost::mpl::or_<type1,type2, type3>::type type;
|
||||
};
|
||||
|
||||
struct error_builder
|
||||
{
|
||||
std::error_code *err;
|
||||
typedef set_on_error result_type;
|
||||
set_on_error get_initializer() {return set_on_error(*err);};
|
||||
void operator()(std::error_code & ec) {err = &ec;};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_tag<std::error_code>
|
||||
{
|
||||
typedef error_tag type;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<error_tag>
|
||||
{
|
||||
typedef error_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
/**The ignore_error property will disable any error handling. This can be useful
|
||||
on linux, where error handling will require a pipe.*/
|
||||
constexpr boost::process::detail::ignore_error_ ignore_error;
|
||||
/**The throw_on_error property will enable the exception when launching a process.
|
||||
It is unnecessary by default, but may be used, when an additional error_code is provided.*/
|
||||
constexpr boost::process::detail::throw_on_error_ throw_on_error;
|
||||
/**
|
||||
The error property will set the executor to handle any errors by setting an
|
||||
[std::error_code](http://en.cppreference.com/w/cpp/error/error_code).
|
||||
|
||||
\code{.cpp}
|
||||
std::error_code ec;
|
||||
system("gcc", error(ec));
|
||||
\endcode
|
||||
|
||||
The following syntax is valid:
|
||||
|
||||
\code{.cpp}
|
||||
error(ec);
|
||||
error=ec;
|
||||
\endcode
|
||||
|
||||
The overload version is achieved by just passing an object of
|
||||
[std::error_code](http://en.cppreference.com/w/cpp/error/error_code) to the function.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::error_ error;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr boost::process::detail::error_ error_ref;
|
||||
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
|
||||
constexpr boost::process::detail::error_ error_code;
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/error.hpp>")
|
||||
#include <boost/process/v1/error.hpp>
|
||||
|
||||
@@ -1,30 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXCEPTION_HPP_
|
||||
#define BOOST_PROCESS_EXCEPTION_HPP_
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
///The exception usually thrown by boost.process.
|
||||
/** It merely inherits [std::system_error](http://en.cppreference.com/w/cpp/error/system_error)
|
||||
* but can then be distinguished in the catch-block from other system errors.
|
||||
*
|
||||
*/
|
||||
struct process_error : std::system_error
|
||||
{
|
||||
using std::system_error::system_error;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_EXCEPTION_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/exception.hpp>")
|
||||
#include <boost/process/v1/exception.hpp>
|
||||
|
||||
@@ -1,97 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXE_HPP
|
||||
#define BOOST_PROCESS_EXE_HPP
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
|
||||
/** \file boost/process/exe.hpp
|
||||
*
|
||||
* Header which provides the exe property.
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::exe">exe</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
namespace boost {
|
||||
namespace filesystem { class path; }
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct exe_
|
||||
{
|
||||
template<typename = void>
|
||||
inline exe_setter_<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & pth) const
|
||||
{
|
||||
return exe_setter_<typename boost::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
|
||||
{
|
||||
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
|
||||
}
|
||||
|
||||
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator()(const Char *s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator= (const Char *s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline exe_setter_<Char> operator= (const std::basic_string<Char> &s) const
|
||||
{
|
||||
return exe_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/** The exe property allows to explicitly set the executable.
|
||||
|
||||
The overload form applies when to the first, when several strings are passed to a launching
|
||||
function.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
|
||||
|
||||
\code{.cpp}
|
||||
exe="value";
|
||||
exe(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::detail::exe_ exe{};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/exe.hpp>")
|
||||
#include <boost/process/v1/exe.hpp>
|
||||
|
||||
@@ -1,343 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_EXTENSIONS_HPP_
|
||||
#define BOOST_PROCESS_EXTENSIONS_HPP_
|
||||
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/posix/executor.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
/** \file boost/process/extend.hpp
|
||||
*
|
||||
* This header which provides the types and functions provided for custom extensions.
|
||||
*
|
||||
* \xmlonly
|
||||
Please refer to the <link linkend="boost_process.extend">tutorial</link> for more details.
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace detail {
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup);
|
||||
}
|
||||
|
||||
|
||||
///Namespace for extensions \attention This is experimental.
|
||||
namespace extend {
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
using windows_executor = ::boost::process::detail::windows::executor<Char, Sequence>;
|
||||
template<typename Sequence>
|
||||
struct posix_executor;
|
||||
|
||||
#elif defined(BOOST_POSIX_API)
|
||||
|
||||
template<typename Sequence>
|
||||
using posix_executor = ::boost::process::detail::posix::executor<Sequence>;
|
||||
template<typename Char, typename Sequence>
|
||||
struct windows_executor;
|
||||
|
||||
#endif
|
||||
|
||||
using ::boost::process::detail::handler;
|
||||
using ::boost::process::detail::api::require_io_context;
|
||||
using ::boost::process::detail::api::async_handler;
|
||||
using ::boost::process::detail::get_io_context;
|
||||
using ::boost::process::detail::get_last_error;
|
||||
using ::boost::process::detail::throw_last_error;
|
||||
using ::boost::process::detail::uses_handles;
|
||||
using ::boost::process::detail::foreach_used_handle;
|
||||
using ::boost::process::detail::get_used_handles;
|
||||
|
||||
///This handler is invoked before the process in launched, to setup parameters. The required signature is `void(Exec &)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_setup_> on_setup;
|
||||
///This handler is invoked if an error occured. The required signature is `void(auto & exec, const std::error_code&)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_error_> on_error;
|
||||
///This handler is invoked if launching the process has succeeded. The required signature is `void(auto & exec)`, where `Exec` is a template parameter.
|
||||
constexpr boost::process::detail::make_handler_t<boost::process::detail::on_success_> on_success;
|
||||
|
||||
#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
|
||||
///This handler is invoked if the fork failed. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_fork_error_ > on_fork_error;
|
||||
///This handler is invoked if the fork succeeded. The required signature is `void(Exec &)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_setup_ > on_exec_setup;
|
||||
///This handler is invoked if the exec call errored. The required signature is `void(auto & exec)`, where `Exec` is a template parameter. \note Only available on posix.
|
||||
constexpr ::boost::process::detail::make_handler_t<::boost::process::detail::posix::on_exec_error_ > on_exec_error;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
///Helper function to get the last error code system-independent
|
||||
inline std::error_code get_last_error();
|
||||
|
||||
///Helper function to get and throw the last system error.
|
||||
/// \throws boost::process::process_error
|
||||
/// \param msg A message to add to the error code.
|
||||
inline void throw_last_error(const std::string & msg);
|
||||
///\overload void throw_last_error(const std::string & msg)
|
||||
inline void throw_last_error();
|
||||
|
||||
|
||||
/** This function gets the io_context from the initializer sequence.
|
||||
*
|
||||
* \attention Yields a compile-time error if no `io_context` is provided.
|
||||
* \param seq The Sequence of the initializer.
|
||||
*/
|
||||
template<typename Sequence>
|
||||
inline asio::io_context& get_io_context(const Sequence & seq);
|
||||
|
||||
/** This class is the base for every initializer, to be used for extensions.
|
||||
*
|
||||
* The usage is done through compile-time polymorphism, so that the required
|
||||
* functions can be overloaded.
|
||||
*
|
||||
* \note None of the function need to be `const`.
|
||||
*
|
||||
*/
|
||||
struct handler
|
||||
{
|
||||
///This function is invoked before the process launch. \note It is not required to be const.
|
||||
template <class Executor>
|
||||
void on_setup(Executor&) const {}
|
||||
|
||||
/** This function is invoked if an error occured while trying to launch the process.
|
||||
* \note It is not required to be const.
|
||||
*/
|
||||
template <class Executor>
|
||||
void on_error(Executor&, const std::error_code &) const {}
|
||||
|
||||
/** This function is invoked if the process was successfully launched.
|
||||
* \note It is not required to be const.
|
||||
*/
|
||||
template <class Executor>
|
||||
void on_success(Executor&) const {}
|
||||
|
||||
/**This function is invoked if an error occured during the call of `fork`.
|
||||
* \note This function will only be called on posix.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_fork_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
/**This function is invoked if the call of `fork` was successful, before
|
||||
* calling `execve`.
|
||||
* \note This function will only be called on posix.
|
||||
* \attention It will be invoked from the new process.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_exec_setup (Executor &) const {}
|
||||
|
||||
/**This function is invoked if the call of `execve` failed.
|
||||
* \note This function will only be called on posix.
|
||||
* \attention It will be invoked from the new process.
|
||||
*/
|
||||
template<typename Executor>
|
||||
void on_exec_error (Executor &, const std::error_code&) const {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Inheriting the class will tell the launching process that an `io_context` is
|
||||
* needed. This should always be used when \ref get_io_context is used.
|
||||
*
|
||||
*/
|
||||
struct require_io_context {};
|
||||
/** Inheriting this class will tell the launching function, that an event handler
|
||||
* shall be invoked when the process exits. This automatically does also inherit
|
||||
* \ref require_io_context.
|
||||
*
|
||||
* You must add the following function to your implementation:
|
||||
*
|
||||
\code{.cpp}
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor & exec)
|
||||
{
|
||||
auto handler_ = this->handler;
|
||||
return [handler_](int exit_code, const std::error_code & ec)
|
||||
{
|
||||
handler_(static_cast<int>(exit_code), ec);
|
||||
};
|
||||
|
||||
}
|
||||
\endcode
|
||||
|
||||
The callback will be obtained by calling this function on setup and it will be
|
||||
invoked when the process exits.
|
||||
|
||||
*
|
||||
* \warning Cannot be used with \ref boost::process::spawn
|
||||
*/
|
||||
struct async_handler : handler, require_io_context
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
///The posix executor type.
|
||||
/** This type represents the posix executor and can be used for overloading in a custom handler.
|
||||
* \note It is an alias for the implementation on posix, and a forward-declaration on windows.
|
||||
*
|
||||
* \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept.
|
||||
|
||||
|
||||
\xmlonly
|
||||
As information for extension development, here is the structure of the process launching (in pseudo-code and uml)
|
||||
<xi:include href="posix_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if when no error occurs.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_success.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if the execution fails.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_exec_err.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence if the fork fails.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/posix_fork_err.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
|
||||
\endxmlonly
|
||||
|
||||
|
||||
\note Error handling if execve fails is done through a pipe, unless \ref ignore_error is used.
|
||||
|
||||
*/
|
||||
template<typename Sequence>
|
||||
struct posix_executor
|
||||
{
|
||||
///A reference to the actual initializer-sequence
|
||||
Sequence & seq;
|
||||
///A pointer to the name of the executable.
|
||||
const char * exe = nullptr;
|
||||
///A pointer to the argument-vector.
|
||||
char *const* cmd_line = nullptr;
|
||||
///A pointer to the environment variables, as default it is set to [environ](http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html)
|
||||
char **env = ::environ;
|
||||
///The pid of the process - it will be -1 before invoking [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html), and after forking either 0 for the new process or a positive value if in the current process. */
|
||||
pid_t pid = -1;
|
||||
///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child.
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
///This function returns a const reference to the error state of the executor.
|
||||
const std::error_code & error() const;
|
||||
|
||||
///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it
|
||||
/// might throw an exception. \note This is the required way to handle errors in initializers.
|
||||
void set_error(const std::error_code &ec, const std::string &msg);
|
||||
///\overload void set_error(const std::error_code &ec, const std::string &msg);
|
||||
void set_error(const std::error_code &ec, const char* msg);
|
||||
};
|
||||
|
||||
///The windows executor type.
|
||||
/** This type represents the posix executor and can be used for overloading in a custom handler.
|
||||
*
|
||||
* \note It is an alias for the implementation on posix, and a forward-declaration on windows.
|
||||
* \tparam Sequence The used initializer-sequence, it is fulfills the boost.fusion [sequence](http://www.boost.org/doc/libs/master/libs/fusion/doc/html/fusion/sequence.html) concept.
|
||||
* \tparam Char The used char-type, either `char` or `wchar_t`.
|
||||
*
|
||||
|
||||
\xmlonly
|
||||
As information for extension development, here is the structure of the process launching (in pseudo-code and uml)<xi:include href="windows_pseudocode.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
<mediaobject>
|
||||
<caption>
|
||||
<para>The sequence for windows process creation.</para>
|
||||
</caption>
|
||||
<imageobject>
|
||||
<imagedata fileref="boost_process/windows_exec.svg"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
\endxmlonly
|
||||
|
||||
*/
|
||||
|
||||
template<typename Char, typename Sequence>
|
||||
struct windows_executor
|
||||
{
|
||||
///A reference to the actual initializer-sequence
|
||||
Sequence & seq;
|
||||
|
||||
///A pointer to the name of the executable. It's null by default.
|
||||
const Char * exe = nullptr;
|
||||
///A pointer to the argument-vector. Must be set by some initializer.
|
||||
char Char* cmd_line = nullptr;
|
||||
///A pointer to the environment variables. It's null by default.
|
||||
char Char* env = nullptr;
|
||||
///A pointer to the working directory. It's null by default.
|
||||
const Char * work_dir = nullptr;
|
||||
|
||||
///A pointer to the process-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It's null by default.
|
||||
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ proc_attrs = nullptr;
|
||||
///A pointer to the thread-attributes of type [SECURITY_ATTRIBUTES](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379560.aspx). It' null by default.
|
||||
::boost::detail::winapi::LPSECURITY_ATTRIBUTES_ thread_attrs = nullptr;
|
||||
///A logical bool value setting whether handles shall be inherited or not.
|
||||
::boost::detail::winapi::BOOL_ inherit_handles = false;
|
||||
|
||||
///The element holding the process-information after process creation. The type is [PROCESS_INFORMATION](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684873.aspx)
|
||||
::boost::detail::winapi::PROCESS_INFORMATION_ proc_info{nullptr, nullptr, 0,0};
|
||||
|
||||
|
||||
///This shared-pointer holds the exit code. It's done this way, so it can be shared between an `asio::io_context` and \ref child.
|
||||
std::shared_ptr<std::atomic<int>> exit_status = std::make_shared<std::atomic<int>>(still_active);
|
||||
|
||||
///This function returns a const reference to the error state of the executor.
|
||||
const std::error_code & error() const;
|
||||
|
||||
///This function can be used to report an error to the executor. This will be handled according to the configuration of the executor, i.e. it
|
||||
/// might throw an exception. \note This is the required way to handle errors in initializers.
|
||||
void set_error(const std::error_code &ec, const std::string &msg);
|
||||
///\overload void set_error(const std::error_code &ec, const std::string &msg);
|
||||
void set_error(const std::error_code &ec, const char* msg);
|
||||
|
||||
///The creation flags of the process
|
||||
::boost::detail::winapi::DWORD_ creation_flags;
|
||||
///The type of the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx), depending on the char-type.
|
||||
typedef typename detail::startup_info<Char>::type startup_info_t;
|
||||
///The type of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx), depending the char-type; only defined with winapi-version equal or higher than 6.
|
||||
typedef typename detail::startup_info_ex<Char>::type startup_info_ex_t;
|
||||
///This function switches the information, so that the extended structure is used. \note It's only defined with winapi-version equal or higher than 6.
|
||||
void set_startup_info_ex();
|
||||
///This element is an instance or a reference (if \ref startup_info_ex exists) to the [startup-info](https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331.aspx) for the process.
|
||||
startup_info_t startup_info;
|
||||
///This element is the instance of the [extended startup-info](https://msdn.microsoft.com/de-de/library/windows/desktop/ms686329.aspx). It is only available with a winapi-version equal or highter than 6.
|
||||
startup_info_ex_t startup_info_ex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/extend.hpp>")
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
|
||||
9
include/boost/process/filesystem.hpp
Normal file
9
include/boost/process/filesystem.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/filesystem.hpp>")
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
@@ -1,228 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/group.hpp
|
||||
*
|
||||
* Defines a group process class.
|
||||
* For additional information see the platform specific implementations:
|
||||
*
|
||||
* - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx)
|
||||
* - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_GROUP_HPP
|
||||
#define BOOST_PROCESS_GROUP_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/none.hpp>
|
||||
#include <atomic>
|
||||
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <boost/process/detail/posix/group_ref.hpp>
|
||||
#include <boost/process/detail/posix/wait_group.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/group_handle.hpp>
|
||||
#include <boost/process/detail/windows/group_ref.hpp>
|
||||
#include <boost/process/detail/windows/wait_group.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
struct group_builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a process group.
|
||||
*
|
||||
* Groups are movable but non-copyable. The destructor
|
||||
* automatically closes handles to the group process.
|
||||
*
|
||||
* The group will have the same interface as std::thread.
|
||||
*
|
||||
* \note If the destructor is called without a previous detach or wait, the group will be terminated.
|
||||
*
|
||||
* \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined.
|
||||
*
|
||||
* \attention Waiting for groups is currently broken on windows and will most likely result in a dead-lock.
|
||||
*/
|
||||
class group
|
||||
{
|
||||
::boost::process::detail::api::group_handle _group_handle;
|
||||
bool _attached = true;
|
||||
public:
|
||||
typedef ::boost::process::detail::api::group_handle group_handle;
|
||||
///Native representation of the handle.
|
||||
typedef group_handle::handle_t native_handle_t;
|
||||
explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {}
|
||||
///Construct the group from a native_handle
|
||||
explicit group(native_handle_t & handle) : _group_handle(handle) {};
|
||||
group(const group&) = delete;
|
||||
///Move constructor
|
||||
group(group && lhs)
|
||||
: _group_handle(std::move(lhs._group_handle)),
|
||||
_attached (lhs._attached)
|
||||
{
|
||||
lhs._attached = false;
|
||||
}
|
||||
///Default constructor
|
||||
group() = default;
|
||||
group& operator=(const group&) = delete;
|
||||
///Move assign
|
||||
group& operator=(group && lhs)
|
||||
{
|
||||
_group_handle= std::move(lhs._group_handle);
|
||||
_attached = lhs._attached;
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
///Detach the group
|
||||
void detach() {_attached = false; }
|
||||
|
||||
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
|
||||
void join() {wait();}
|
||||
/** Check if the child is joinable. */
|
||||
bool joinable() {return _attached;}
|
||||
|
||||
/** Destructor
|
||||
*
|
||||
* \note If the destructor is called without a previous detach or wait, the group will be terminated.
|
||||
*
|
||||
*/
|
||||
~group()
|
||||
{
|
||||
std::error_code ec;
|
||||
if ( _attached && valid())
|
||||
terminate(ec);
|
||||
}
|
||||
|
||||
///Obtain the native handle of the group.
|
||||
native_handle_t native_handle() const { return _group_handle.handle(); }
|
||||
|
||||
///Wait for the process group to exit.
|
||||
void wait()
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle);
|
||||
}
|
||||
///\overload void wait()
|
||||
void wait(std::error_code & ec) noexcept
|
||||
{
|
||||
boost::process::detail::api::wait(_group_handle, ec);
|
||||
}
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
}
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
template< class Rep, class Period >
|
||||
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);
|
||||
}
|
||||
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
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 >
|
||||
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);
|
||||
}
|
||||
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
return _group_handle.valid();
|
||||
}
|
||||
///Convenience to call valid.
|
||||
explicit operator bool() const {return valid();}
|
||||
|
||||
///Terminate the process group, i.e. all processes in the group
|
||||
void terminate()
|
||||
{
|
||||
::boost::process::detail::api::terminate(_group_handle);
|
||||
}
|
||||
///\overload void terminate()
|
||||
void terminate(std::error_code & ec) noexcept
|
||||
{
|
||||
::boost::process::detail::api::terminate(_group_handle, ec);
|
||||
}
|
||||
|
||||
///Assign a child process to the group
|
||||
void add(const child &c)
|
||||
{
|
||||
_group_handle.add(c.native_handle());
|
||||
}
|
||||
///\overload void assign(const child & c)
|
||||
void add(const child &c, std::error_code & ec) noexcept
|
||||
{
|
||||
_group_handle.add(c.native_handle(), ec);
|
||||
}
|
||||
|
||||
///Check if the child process is in the group
|
||||
bool has(const child &c)
|
||||
{
|
||||
return _group_handle.has(c.native_handle());
|
||||
}
|
||||
///\overload bool has(const child &)
|
||||
bool has(const child &c, std::error_code & ec) noexcept
|
||||
{
|
||||
return _group_handle.has(c.native_handle(), ec);
|
||||
|
||||
}
|
||||
|
||||
friend struct detail::group_builder;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct group_tag;
|
||||
struct group_builder
|
||||
{
|
||||
group * group_p;
|
||||
|
||||
void operator()(group & grp) {this->group_p = &grp;};
|
||||
|
||||
typedef api::group_ref result_type;
|
||||
api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);};
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_tag<group>
|
||||
{
|
||||
typedef group_tag type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct initializer_builder<group_tag>
|
||||
{
|
||||
typedef group_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/group.hpp>")
|
||||
#include <boost/process/v1/group.hpp>
|
||||
|
||||
@@ -1,107 +1,9 @@
|
||||
// Copyright (c) 2019 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_HANDLES_HPP_
|
||||
#define BOOST_PROCESS_HANDLES_HPP_
|
||||
|
||||
/**
|
||||
* \file boost/process/handles.hpp
|
||||
*
|
||||
* Defines functions to obtain handles of the current process and limit the amount for inherited ones.
|
||||
*/
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handles.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handles.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace this_process
|
||||
{
|
||||
|
||||
///The native type for handles
|
||||
using native_handle_type = ::boost::process::detail::api::native_handle_type;
|
||||
|
||||
/**
|
||||
* Get a snapshot of all handles of the process (i.e. file descriptors on posix and handles on windows) of the current process.
|
||||
*
|
||||
* \note This function might not work on certain posix systems.
|
||||
*
|
||||
* \note On Windows version older than windows 8 this function will iterate all the system handles, meaning it might be quite slow.
|
||||
*
|
||||
* \warning This functionality is utterly prone to race conditions, since other threads might open or close handles.
|
||||
*
|
||||
* \return The list of all open handles of the current process
|
||||
*/
|
||||
inline std::vector<native_handle_type> get_handles()
|
||||
{
|
||||
return ::boost::process::detail::api::get_handles();
|
||||
}
|
||||
|
||||
|
||||
/** \overload std::vector<native_handle_type> get_handles() */
|
||||
inline std::vector<native_handle_type> get_handles(std::error_code &ec)
|
||||
{
|
||||
return ::boost::process::detail::api::get_handles(ec);
|
||||
}
|
||||
|
||||
/** Determines if a given handle is a a stream-handle, i.e. any handle that can be used with read and write functions.
|
||||
* Stream handles include pipes, regular files and sockets.
|
||||
*
|
||||
* \return Indicates if it's a stream handle.
|
||||
*/
|
||||
inline bool is_stream_handle(native_handle_type handle)
|
||||
{
|
||||
return ::boost::process::detail::api::is_stream_handle(handle);
|
||||
}
|
||||
|
||||
|
||||
/** \overload bool is_stream_handle(native_handle_type handle) */
|
||||
inline bool is_stream_handle(native_handle_type handle, std::error_code &ec)
|
||||
{
|
||||
return ::boost::process::detail::api::is_stream_handle(handle, ec);
|
||||
}
|
||||
|
||||
}
|
||||
namespace process
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
using limit_handles_ = ::boost::process::detail::api::limit_handles_;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The limit_handles property sets all properties to be inherited only expcitly. It closes all unused file-descriptors on posix after the fork and
|
||||
* removes the inherit flags on windows.
|
||||
*
|
||||
* \note This is executed after the fork on posix.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles);
|
||||
* \endcode
|
||||
*
|
||||
* Since limit also closes the standard handles unless they are explicitly redirected they can be ignored by `limit_handles` in the following way.
|
||||
*
|
||||
* \code{.cpp}
|
||||
* system("gcc", limit_handles.allowStd())
|
||||
* \endcode
|
||||
*
|
||||
*/
|
||||
const static ::boost::process::detail::api::limit_handles_ limit_handles;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BOOST_PROCESS_HANDLES_HPP_
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/handles.hpp>")
|
||||
#include <boost/process/v1/handles.hpp>
|
||||
|
||||
@@ -1,551 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_IO_HPP_
|
||||
#define BOOST_PROCESS_IO_HPP_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
|
||||
#include <future>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#include <boost/process/detail/posix/close_in.hpp>
|
||||
#include <boost/process/detail/posix/close_out.hpp>
|
||||
#include <boost/process/detail/posix/null_in.hpp>
|
||||
#include <boost/process/detail/posix/null_out.hpp>
|
||||
#include <boost/process/detail/posix/file_in.hpp>
|
||||
#include <boost/process/detail/posix/file_out.hpp>
|
||||
#include <boost/process/detail/posix/pipe_in.hpp>
|
||||
#include <boost/process/detail/posix/pipe_out.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/detail/windows/close_in.hpp>
|
||||
#include <boost/process/detail/windows/close_out.hpp>
|
||||
#include <boost/process/detail/windows/null_in.hpp>
|
||||
#include <boost/process/detail/windows/null_out.hpp>
|
||||
#include <boost/process/detail/windows/file_in.hpp>
|
||||
#include <boost/process/detail/windows/file_out.hpp>
|
||||
#include <boost/process/detail/windows/pipe_in.hpp>
|
||||
#include <boost/process/detail/windows/pipe_out.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/io.hpp
|
||||
*
|
||||
* Header which provides the io properties. It provides the following properties:
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::close">close</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::null">null</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::std_in">std_in</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::std_out">std_out</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::std_err">std_err</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
|
||||
\par File I/O
|
||||
|
||||
The library allows full redirection of streams to files as shown below.
|
||||
|
||||
\code{.cpp}
|
||||
boost::filesystem::path log = "my_log_file.txt";
|
||||
boost::filesystem::path input = "input.txt";
|
||||
boost::filesystem::path output = "output.txt";
|
||||
system("my_prog", std_out>output, std_in<input, std_err>log);
|
||||
\endcode
|
||||
|
||||
\par Synchronous Pipe I/O
|
||||
|
||||
Another way is to communicate through pipes.
|
||||
|
||||
\code{.cpp}
|
||||
pstream str;
|
||||
child c("my_prog", std_out > str);
|
||||
|
||||
int i;
|
||||
str >> i;
|
||||
\endcode
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
\par Asynchronous I/O
|
||||
|
||||
Utilizing `boost.asio` asynchronous I/O is provided.
|
||||
|
||||
\code
|
||||
boost::asio::io_context ios;
|
||||
std::future<std::string> output;
|
||||
system("ls", std_out > output, ios);
|
||||
|
||||
auto res = fut.get();
|
||||
\endcode
|
||||
|
||||
\note `boost/process/async.hpp` must also be included for this to work.
|
||||
|
||||
\par Closing
|
||||
|
||||
Stream can be closed, so nothing can be read or written.
|
||||
|
||||
\code{.cpp}
|
||||
system("foo", std_in.close());
|
||||
\endcode
|
||||
|
||||
\par Null
|
||||
|
||||
Streams can be redirected to null, which means, that written date will be
|
||||
discarded and read data will only contain `EOF`.
|
||||
|
||||
\code{.cpp}
|
||||
system("b2", std_out > null);
|
||||
\endcode
|
||||
|
||||
*
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
template<typename T> using is_streambuf = typename std::is_same<T, boost::asio::streambuf>::type;
|
||||
template<typename T> using is_const_buffer =
|
||||
std::integral_constant<bool,
|
||||
std::is_same< boost::asio::const_buffer, T>::value |
|
||||
std::is_base_of<boost::asio::const_buffer, T>::value
|
||||
>;
|
||||
template<typename T> using is_mutable_buffer =
|
||||
std::integral_constant<bool,
|
||||
std::is_same< boost::asio::mutable_buffer, T>::value |
|
||||
std::is_base_of<boost::asio::mutable_buffer, T>::value
|
||||
>;
|
||||
|
||||
|
||||
struct null_t {constexpr null_t() = default;};
|
||||
struct close_t;
|
||||
|
||||
template<class>
|
||||
struct 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();}
|
||||
api::close_in operator<(const close_t &) const {return api::close_in();}
|
||||
|
||||
api::null_in null() const {return api::null_in();}
|
||||
api::null_in operator=(const null_t &) const {return api::null_in();}
|
||||
api::null_in operator<(const null_t &) const {return api::null_in();}
|
||||
|
||||
api::file_in operator=(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator=(const std::string & p) const {return p;}
|
||||
api::file_in operator=(const std::wstring &p) const {return p;}
|
||||
api::file_in operator=(const char * p) const {return p;}
|
||||
api::file_in operator=(const wchar_t * p) const {return p;}
|
||||
|
||||
api::file_in operator<(const boost::filesystem::path &p) const {return p;}
|
||||
api::file_in operator<(const std::string &p) const {return p;}
|
||||
api::file_in operator<(const std::wstring &p) const {return p;}
|
||||
api::file_in operator<(const char*p) const {return p;}
|
||||
api::file_in operator<(const wchar_t * p) const {return p;}
|
||||
|
||||
api::file_in operator=(FILE * f) const {return f;}
|
||||
api::file_in operator<(FILE * f) const {return f;}
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_opstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_in operator<(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::async_pipe_in operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_in operator<(async_pipe & p) const {return p;}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator=(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator=(T & buf) const {return buf;}
|
||||
|
||||
template<typename T, typename = typename std::enable_if<
|
||||
is_const_buffer<T>::value || is_mutable_buffer<T>::value
|
||||
>::type>
|
||||
api::async_in_buffer<const T> operator<(const T & buf) const {return buf;}
|
||||
template<typename T, typename = typename std::enable_if<is_streambuf<T>::value>::type >
|
||||
api::async_in_buffer<T> operator<(T & buf) const {return buf;}
|
||||
|
||||
};
|
||||
|
||||
//-1 == empty.
|
||||
//1 == stdout
|
||||
//2 == stderr
|
||||
template<int p1, int p2 = -1>
|
||||
struct 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>();}
|
||||
api::close_out<p1,p2> operator>(const close_t &) const {return api::close_out<p1,p2>();}
|
||||
|
||||
api::null_out<p1,p2> null() const {return api::null_out<p1,p2>();}
|
||||
api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
|
||||
|
||||
api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
api::file_out<p1,p2> operator=(FILE * f) const {return f;}
|
||||
api::file_out<p1,p2> operator>(FILE * f) const {return f;}
|
||||
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pipe<Char, Traits> & p) const {return p;}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_ipstream<Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator=(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
template<typename Char, typename Traits> api::pipe_out<p1,p2> operator>(basic_pstream <Char, Traits> & p) const {return p.pipe();}
|
||||
|
||||
api::async_pipe_out<p1, p2> operator=(async_pipe & p) const {return p;}
|
||||
api::async_pipe_out<p1, p2> operator>(async_pipe & p) const {return p;}
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator=(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator=(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator=(asio::streambuf & os) const {return os ;}
|
||||
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffer> operator>(const asio::mutable_buffer & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, const asio::mutable_buffers_1> operator>(const asio::mutable_buffers_1 & buf) const {return buf;}
|
||||
api::async_out_buffer<p1, p2, asio::streambuf> operator>(asio::streambuf & os) const {return os ;}
|
||||
|
||||
api::async_out_future<p1,p2, std::string> operator=(std::future<std::string> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::string> operator>(std::future<std::string> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::vector<char>> operator=(std::future<std::vector<char>> & fut) const { return fut;}
|
||||
api::async_out_future<p1,p2, std::vector<char>> operator>(std::future<std::vector<char>> & fut) const { return fut;}
|
||||
|
||||
template<int pin, typename = typename std::enable_if<
|
||||
(((p1 == 1) && (pin == 2)) ||
|
||||
((p1 == 2) && (pin == 1)))
|
||||
&& (p2 == -1)>::type>
|
||||
constexpr std_out_<1, 2> operator& (const std_out_<pin>&) const
|
||||
{
|
||||
return std_out_<1, 2> ();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct 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>();}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
///This constant is a utility to allow syntax like `std_out > close` for closing I/O streams.
|
||||
constexpr boost::process::detail::close_t close;
|
||||
///This constant is a utility to redirect streams to the null-device.
|
||||
constexpr boost::process::detail::null_t null;
|
||||
|
||||
/**
|
||||
This property allows to set the input stream for the child process.
|
||||
|
||||
\section stdin_details Details
|
||||
|
||||
\subsection stdin_file File Input
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
|
||||
with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
FILE* is explicitly added, so the process can easily redirect the output stream
|
||||
of the child to another output stream of the process. That is:
|
||||
|
||||
\code{.cpp}
|
||||
system("ls", std_in < stdin);
|
||||
\endcode
|
||||
|
||||
\warning If the launching and the child process use the input, this leads to undefined behaviour.
|
||||
|
||||
A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
|
||||
implementation not providing access to the handle.
|
||||
|
||||
The valid expressions for this property are
|
||||
|
||||
\code{.cpp}
|
||||
std_in < file;
|
||||
std_in = file;
|
||||
\endcode
|
||||
|
||||
\subsection stdin_pipe Pipe Input
|
||||
|
||||
As explained in the corresponding section, the boost.process library provides a
|
||||
@ref boost::process::async_pipe "async_pipe" class which can be
|
||||
used to communicate with child processes.
|
||||
|
||||
\note Technically the @ref boost::process::async_pipe "async_pipe"
|
||||
works synchronous here, since no asio implementation is used by the library here.
|
||||
The async-operation will then however not end if the process is finished, since
|
||||
the pipe remains open. You can use the async_close function with on_exit to fix that.
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
\code{.cpp}
|
||||
std_in < pipe;
|
||||
std_in = pipe;
|
||||
\endcode
|
||||
|
||||
Where the valid types for `pipe` are the following:
|
||||
|
||||
- `basic_pipe`
|
||||
- `async_pipe`
|
||||
- `basic_opstream`
|
||||
- `basic_pstream`
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
\subsection stdin_async_pipe Asynchronous Pipe Input
|
||||
|
||||
Asynchronous Pipe I/O classifies communication which has automatically handling
|
||||
of the asynchronous operations by the process library. This means, that a pipe will be
|
||||
constructed, the async_read/-write will be automatically started, and that the
|
||||
end of the child process will also close the pipe.
|
||||
|
||||
Valid types for pipe I/O are the following:
|
||||
|
||||
- `boost::asio::const_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::streambuf`
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
\code{.cpp}
|
||||
std_in < buffer;
|
||||
std_in = buffer;
|
||||
std_out > buffer;
|
||||
std_out = buffer;
|
||||
std_err > buffer;
|
||||
std_err = buffer;
|
||||
(std_out & std_err) > buffer;
|
||||
(std_out & std_err) = buffer;
|
||||
\endcode
|
||||
|
||||
\note It is also possible to get a future for std_in, by chaining another `std::future<void>` onto it,
|
||||
so you can wait for the input to be completed. It looks like this:
|
||||
\code{.cpp}
|
||||
std::future<void> fut;
|
||||
boost::asio::io_context ios;
|
||||
std::string data;
|
||||
child c("prog", std_in < buffer(data) > fut, ios);
|
||||
fut.get();
|
||||
\endcode
|
||||
|
||||
|
||||
\note `boost::asio::buffer` is also available in the `boost::process` namespace.
|
||||
|
||||
\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function.
|
||||
|
||||
|
||||
\subsection stdin_close Close
|
||||
|
||||
The input stream can be closed, so it cannot be read from. This will lead to an error when attempted.
|
||||
|
||||
This can be achieved by the following syntax.
|
||||
|
||||
\code{.cpp}
|
||||
std_in < close;
|
||||
std_in = close;
|
||||
std_in.close();
|
||||
\endcode
|
||||
|
||||
\subsection stdin_null Null
|
||||
|
||||
The input stream can be redirected to read from the null-device, which means that only `EOF` is read.
|
||||
|
||||
The syntax to achieve that has the following variants:
|
||||
|
||||
\code{.cpp}
|
||||
std_in < null;
|
||||
std_in = null;
|
||||
std_in.null();
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
constexpr boost::process::detail::std_in_<void> std_in;
|
||||
|
||||
/**
|
||||
This property allows to set the output stream for the child process.
|
||||
|
||||
\note The Semantic is the same as for \xmlonly <globalname alt="boost::process::std_err">std_err</globalname> \endxmlonly
|
||||
|
||||
\note `std_err` and `std_out` can be combined into one stream, with the `operator &`, i.e. `std_out & std_err`.
|
||||
|
||||
\section stdout_details Details
|
||||
|
||||
\subsection stdout_file File Input
|
||||
|
||||
The file I/O simple redirects the stream to a file, for which the possible types are
|
||||
|
||||
- `boost::filesystem::path`
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type*`
|
||||
- `FILE*`
|
||||
|
||||
with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
FILE* is explicitly added, so the process can easily redirect the output stream
|
||||
of the child to another output stream of the process. That is:
|
||||
|
||||
\code{.cpp}
|
||||
system("ls", std_out < stdin);
|
||||
\endcode
|
||||
|
||||
\warning If the launching and the child process use the input, this leads to undefined behaviour.
|
||||
|
||||
A syntax like `system("ls", std_out > std::cerr)` is not possible, due to the C++
|
||||
implementation not providing access to the handle.
|
||||
|
||||
The valid expressions for this property are
|
||||
|
||||
\code{.cpp}
|
||||
std_out < file;
|
||||
std_out = file;
|
||||
\endcode
|
||||
|
||||
\subsection stdout_pipe Pipe Output
|
||||
|
||||
As explained in the corresponding section, the boost.process library provides a
|
||||
@ref boost::process::async_pipe "async_pipe" class which can be
|
||||
used to communicate with child processes.
|
||||
|
||||
\note Technically the @ref boost::process::async_pipe "async_pipe"
|
||||
works like a synchronous pipe here, since no asio implementation is used by the library here.
|
||||
The asynchronous operation will then however not end if the process is finished, since
|
||||
the pipe remains open. You can use the async_close function with on_exit to fix that.
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
\code{.cpp}
|
||||
std_out > pipe;
|
||||
std_out = pipe;
|
||||
\endcode
|
||||
|
||||
Where the valid types for `pipe` are the following:
|
||||
|
||||
- `basic_pipe`
|
||||
- `async_pipe`
|
||||
- `basic_ipstream`
|
||||
- `basic_pstream`
|
||||
|
||||
Note that the pipe may also be used between several processes, like this:
|
||||
|
||||
\code{.cpp}
|
||||
pipe p;
|
||||
child c1("nm", "a.out", std_out>p);
|
||||
child c2("c++filt", std_in<p);
|
||||
\endcode
|
||||
|
||||
\subsection stdout_async_pipe Asynchronous Pipe Output
|
||||
|
||||
Asynchronous Pipe I/O classifies communication which has automatically handling
|
||||
of the async operations by the process library. This means, that a pipe will be
|
||||
constructed, the async_read/-write will be automatically started, and that the
|
||||
end of the child process will also close the pipe.
|
||||
|
||||
Valid types for pipe I/O are the following:
|
||||
|
||||
- `boost::asio::mutable_buffer` \xmlonly <footnote><para> Constructed with <code>boost::asio::buffer</code></para></footnote> \endxmlonly
|
||||
- `boost::asio::streambuf`
|
||||
- `std::future<std::vector<char>>`
|
||||
- `std::future<std::string>`
|
||||
|
||||
Valid expressions with pipes are these:
|
||||
|
||||
\code{.cpp}
|
||||
std_out > buffer;
|
||||
std_out = buffer;
|
||||
std_err > buffer;
|
||||
std_err = buffer;
|
||||
(std_out & std_err) > buffer;
|
||||
(std_out & std_err) = buffer;
|
||||
\endcode
|
||||
|
||||
\note `boost::asio::buffer` is also available in the `boost::process` namespace.
|
||||
|
||||
\warning This feature requires `boost/process/async.hpp` to be included and a reference to `boost::asio::io_context` to be passed to the launching function.
|
||||
|
||||
|
||||
\subsection stdout_close Close
|
||||
|
||||
The out stream can be closed, so it cannot be write from.
|
||||
This will lead to an error when attempted.
|
||||
|
||||
This can be achieved by the following syntax.
|
||||
|
||||
\code{.cpp}
|
||||
std_out > close;
|
||||
std_out = close;
|
||||
std_out.close();
|
||||
\endcode
|
||||
|
||||
\subsection stdout_null Null
|
||||
|
||||
The output stream can be redirected to write to the null-device,
|
||||
which means that all output is discarded.
|
||||
|
||||
The syntax to achieve that has the following variants:
|
||||
|
||||
\code{.cpp}
|
||||
std_out > null;
|
||||
std_out = null;
|
||||
std_out.null();
|
||||
\endcode
|
||||
|
||||
*/
|
||||
|
||||
constexpr boost::process::detail::std_out_<1> std_out;
|
||||
/**This property allows setting the `stderr` stream. The semantic and syntax is the same as for
|
||||
* \xmlonly <globalname alt="boost::process::std_out">std_out</globalname> \endxmlonly .
|
||||
*/
|
||||
constexpr boost::process::detail::std_out_<2> std_err;
|
||||
|
||||
}}
|
||||
#endif /* INCLUDE_BOOST_PROCESS_IO_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/io.hpp>")
|
||||
#include <boost/process/v1/io.hpp>
|
||||
|
||||
@@ -1,246 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2008 Beman Dawes
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_LOCALE_HPP_
|
||||
#define BOOST_PROCESS_LOCALE_HPP_
|
||||
|
||||
#include <system_error>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/locale.hpp>
|
||||
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
|
||||
|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||||
#include <codecvt>
|
||||
#endif
|
||||
|
||||
#include <locale>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
class codecvt_category_t : public std::error_category
|
||||
{
|
||||
public:
|
||||
codecvt_category_t() = default;
|
||||
const char* name() const noexcept override {return "codecvt";}
|
||||
std::string message(int ev) const override
|
||||
{
|
||||
std::string str;
|
||||
switch (ev)
|
||||
{
|
||||
case std::codecvt_base::ok:
|
||||
str = "ok";
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
str = "partial";
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
str = "error";
|
||||
break;
|
||||
case std::codecvt_base::noconv:
|
||||
str = "noconv";
|
||||
break;
|
||||
default:
|
||||
str = "unknown error";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
///Internally used error cateory for code conversion.
|
||||
inline const std::error_category& codecvt_category()
|
||||
{
|
||||
static const ::boost::process::detail::codecvt_category_t cat;
|
||||
return cat;
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
//copied from boost.filesystem
|
||||
inline std::locale default_locale()
|
||||
{
|
||||
# if defined(BOOST_WINDOWS_API)
|
||||
std::locale global_loc = std::locale();
|
||||
return std::locale(global_loc, new boost::process::detail::windows::windows_file_codecvt);
|
||||
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
|
||||
|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||||
std::locale global_loc = std::locale();
|
||||
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
|
||||
# else // Other POSIX
|
||||
// ISO C calls std::locale("") "the locale-specific native environment", and this
|
||||
// locale is the default for many POSIX-based operating systems such as Linux.
|
||||
return std::locale("");
|
||||
# endif
|
||||
}
|
||||
|
||||
inline std::locale& process_locale()
|
||||
{
|
||||
static std::locale loc(default_locale());
|
||||
return loc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///The internally used type for code conversion.
|
||||
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
|
||||
|
||||
///Get a reference to the currently used code converter.
|
||||
inline const codecvt_type& codecvt()
|
||||
{
|
||||
return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
|
||||
detail::process_locale());
|
||||
}
|
||||
|
||||
///Set the locale of the library.
|
||||
inline std::locale imbue(const std::locale& loc)
|
||||
{
|
||||
std::locale temp(detail::process_locale());
|
||||
detail::process_locale() = loc;
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
inline std::size_t convert(const char* from,
|
||||
const char* from_end,
|
||||
wchar_t* to, wchar_t* to_end,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
|
||||
const char* from_next;
|
||||
wchar_t* to_next;
|
||||
|
||||
auto res = cvt.in(state, from, from_end, from_next,
|
||||
to, to_end, to_next);
|
||||
|
||||
if (res != std::codecvt_base::ok)
|
||||
throw process_error(res, ::boost::process::codecvt_category(),
|
||||
"boost::process codecvt to wchar_t");
|
||||
|
||||
|
||||
return to_next - to;
|
||||
|
||||
}
|
||||
|
||||
inline std::size_t convert(const wchar_t* from,
|
||||
const wchar_t* from_end,
|
||||
char* to, char* to_end,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
|
||||
const wchar_t* from_next;
|
||||
char* to_next;
|
||||
|
||||
std::codecvt_base::result res;
|
||||
|
||||
if ((res=cvt.out(state, from, from_end, from_next,
|
||||
to, to_end, to_next)) != std::codecvt_base::ok)
|
||||
throw process_error(res, ::boost::process::codecvt_category(),
|
||||
"boost::process codecvt to char");
|
||||
|
||||
return to_next - to;
|
||||
}
|
||||
|
||||
inline std::wstring convert(const std::string & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::wstring out(st.size() + 10, ' '); //just to be sure
|
||||
auto sz = convert(st.c_str(), st.c_str() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string convert(const std::wstring & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::string out(st.size() * 2, ' '); //just to be sure
|
||||
auto sz = convert(st.c_str(), st.c_str() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::vector<wchar_t> convert(const std::vector<char> & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::vector<wchar_t> out(st.size() + 10); //just to be sure
|
||||
auto sz = convert(st.data(), st.data() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::vector<char> convert(const std::vector<wchar_t> & st,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
std::vector<char> out(st.size() * 2); //just to be sure
|
||||
auto sz = convert(st.data(), st.data() + st.size(),
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
inline std::wstring convert(const char *begin, const char* end,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
auto size = end-begin;
|
||||
std::wstring out(size + 10, ' '); //just to be sure
|
||||
using namespace std;
|
||||
auto sz = convert(begin, end,
|
||||
&out.front(), &out.back(), cvt);
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::string convert(const wchar_t * begin, const wchar_t *end,
|
||||
const ::boost::process::codecvt_type & cvt =
|
||||
::boost::process::codecvt())
|
||||
{
|
||||
auto size = end-begin;
|
||||
|
||||
std::string out(size * 2, ' '); //just to be sure
|
||||
auto sz = convert(begin, end ,
|
||||
&out.front(), &out.back(), cvt);
|
||||
|
||||
out.resize(sz);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/locale.hpp>")
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
@@ -1,625 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_PIPE_HPP
|
||||
#define BOOST_PROCESS_PIPE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <streambuf>
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/basic_pipe.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/basic_pipe.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
using ::boost::process::detail::api::basic_pipe;
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** Class implementation of a pipe.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
class basic_pipe
|
||||
{
|
||||
public:
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
typedef ::boost::detail::winapi::HANDLE_ native_handle;
|
||||
|
||||
/// Default construct the pipe. Will be opened.
|
||||
basic_pipe();
|
||||
|
||||
///Construct a named pipe.
|
||||
inline explicit basic_pipe(const std::string & name);
|
||||
/** Copy construct the pipe.
|
||||
* \note Duplicated the handles.
|
||||
*/
|
||||
inline basic_pipe(const basic_pipe& p);
|
||||
/** Move construct the pipe. */
|
||||
basic_pipe(basic_pipe&& lhs);
|
||||
/** Copy assign the pipe.
|
||||
* \note Duplicated the handles.
|
||||
*/
|
||||
inline basic_pipe& operator=(const basic_pipe& p);
|
||||
/** Move assign the pipe. */
|
||||
basic_pipe& operator=(basic_pipe&& lhs);
|
||||
/** Destructor closes the handles. */
|
||||
~basic_pipe();
|
||||
/** Get the native handle of the source. */
|
||||
native_handle native_source() const;
|
||||
/** Get the native handle of the sink. */
|
||||
native_handle native_sink () const;
|
||||
|
||||
/** Assign a new value to the source */
|
||||
void assign_source(native_handle h);
|
||||
/** Assign a new value to the sink */
|
||||
void assign_sink (native_handle h);
|
||||
|
||||
|
||||
///Write data to the pipe.
|
||||
int_type write(const char_type * data, int_type count);
|
||||
///Read data from the pipe.
|
||||
int_type read(char_type * data, int_type count);
|
||||
///Check if the pipe is open.
|
||||
bool is_open();
|
||||
///Close the pipe
|
||||
void close();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
typedef basic_pipe<char> pipe;
|
||||
typedef basic_pipe<wchar_t> wpipe;
|
||||
|
||||
|
||||
/** Implementation of the stream buffer for a pipe.
|
||||
*/
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
|
||||
{
|
||||
typedef basic_pipe<CharT, Traits> pipe_type;
|
||||
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
|
||||
constexpr static int default_buffer_size = BOOST_PROCESS_PIPE_SIZE;
|
||||
|
||||
///Default constructor, will also construct the pipe.
|
||||
basic_pipebuf() : _write(default_buffer_size), _read(default_buffer_size)
|
||||
{
|
||||
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
|
||||
this->setp(_write.data(), _write.data() + _write.size());
|
||||
}
|
||||
///Copy Constructor.
|
||||
basic_pipebuf(const basic_pipebuf & ) = default;
|
||||
///Move Constructor
|
||||
basic_pipebuf(basic_pipebuf && ) = default;
|
||||
|
||||
///Destructor -> writes the frest of the data
|
||||
~basic_pipebuf()
|
||||
{
|
||||
if (basic_pipebuf::is_open())
|
||||
basic_pipebuf::overflow(Traits::eof());
|
||||
}
|
||||
|
||||
///Move construct from a pipe.
|
||||
basic_pipebuf(pipe_type && p) : _pipe(std::move(p)),
|
||||
_write(default_buffer_size),
|
||||
_read(default_buffer_size)
|
||||
{
|
||||
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
|
||||
this->setp(_write.data(), _write.data() + _write.size());
|
||||
}
|
||||
///Construct from a pipe.
|
||||
basic_pipebuf(const pipe_type & p) : _pipe(p),
|
||||
_write(default_buffer_size),
|
||||
_read(default_buffer_size)
|
||||
{
|
||||
this->setg(_read.data(), _read.data()+ 128, _read.data() + 128);
|
||||
this->setp(_write.data(), _write.data() + _write.size());
|
||||
}
|
||||
///Copy assign.
|
||||
basic_pipebuf& operator=(const basic_pipebuf & ) = delete;
|
||||
///Move assign.
|
||||
basic_pipebuf& operator=(basic_pipebuf && ) = default;
|
||||
///Move assign a pipe.
|
||||
basic_pipebuf& operator=(pipe_type && p)
|
||||
{
|
||||
_pipe = std::move(p);
|
||||
return *this;
|
||||
}
|
||||
///Copy assign a pipe.
|
||||
basic_pipebuf& operator=(const pipe_type & p)
|
||||
{
|
||||
_pipe = p;
|
||||
return *this;
|
||||
}
|
||||
///Writes characters to the associated output sequence from the put area
|
||||
int_type overflow(int_type ch = traits_type::eof()) override
|
||||
{
|
||||
if (_pipe.is_open() && (ch != traits_type::eof()))
|
||||
{
|
||||
if (this->pptr() == this->epptr())
|
||||
{
|
||||
bool wr = this->_write_impl();
|
||||
if (wr)
|
||||
{
|
||||
*this->pptr() = ch;
|
||||
this->pbump(1);
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*this->pptr() = ch;
|
||||
this->pbump(1);
|
||||
if (this->_write_impl())
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
else if (ch == traits_type::eof())
|
||||
this->sync();
|
||||
|
||||
return traits_type::eof();
|
||||
}
|
||||
///Synchronizes the buffers with the associated character sequence
|
||||
int sync() override { return this->_write_impl() ? 0 : -1; }
|
||||
|
||||
///Reads characters from the associated input sequence to the get area
|
||||
int_type underflow() override
|
||||
{
|
||||
if (!_pipe.is_open())
|
||||
return traits_type::eof();
|
||||
|
||||
if (this->egptr() == &_read.back()) //ok, so we're at the end of the buffer
|
||||
this->setg(_read.data(), _read.data()+ 10, _read.data() + 10);
|
||||
|
||||
|
||||
auto len = &_read.back() - this->egptr() ;
|
||||
auto res = _pipe.read(
|
||||
this->egptr(),
|
||||
static_cast<typename pipe_type::int_type>(len));
|
||||
if (res == 0)
|
||||
return traits_type::eof();
|
||||
|
||||
this->setg(this->eback(), this->gptr(), this->egptr() + res);
|
||||
auto val = *this->gptr();
|
||||
|
||||
return traits_type::to_int_type(val);
|
||||
}
|
||||
|
||||
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(pipe_type&& p) {_pipe = std::move(p); }
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(const pipe_type& p) {_pipe = p; }
|
||||
///Get a reference to the pipe.
|
||||
pipe_type & pipe() & {return _pipe;}
|
||||
///Get a const reference to the pipe.
|
||||
const pipe_type &pipe() const & {return _pipe;}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_pipe);}
|
||||
|
||||
///Check if the pipe is open
|
||||
bool is_open() const {return _pipe.is_open(); }
|
||||
|
||||
///Open a new pipe
|
||||
basic_pipebuf<CharT, Traits>* open()
|
||||
{
|
||||
if (is_open())
|
||||
return nullptr;
|
||||
_pipe = pipe();
|
||||
return this;
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
basic_pipebuf<CharT, Traits>* open(const std::string & name)
|
||||
{
|
||||
if (is_open())
|
||||
return nullptr;
|
||||
_pipe = pipe(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
basic_pipebuf<CharT, Traits>* close()
|
||||
{
|
||||
if (!is_open())
|
||||
return nullptr;
|
||||
overflow(Traits::eof());
|
||||
return this;
|
||||
}
|
||||
private:
|
||||
pipe_type _pipe;
|
||||
std::vector<char_type> _write;
|
||||
std::vector<char_type> _read;
|
||||
|
||||
bool _write_impl()
|
||||
{
|
||||
if (!_pipe.is_open())
|
||||
return false;
|
||||
|
||||
auto base = this->pbase();
|
||||
|
||||
if (base == this->pptr())
|
||||
return true;
|
||||
|
||||
std::ptrdiff_t wrt = _pipe.write(base,
|
||||
static_cast<typename pipe_type::int_type>(this->pptr() - base));
|
||||
|
||||
std::ptrdiff_t diff = this->pptr() - base;
|
||||
|
||||
if (wrt < diff)
|
||||
std::move(base + wrt, base + diff, base);
|
||||
else if (wrt == 0) //broken pipe
|
||||
return false;
|
||||
|
||||
this->pbump(-wrt);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_pipebuf<char> pipebuf;
|
||||
typedef basic_pipebuf<wchar_t> wpipebuf;
|
||||
|
||||
/** Implementation of a reading pipe stream.
|
||||
*
|
||||
*/
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
class basic_ipstream : public std::basic_istream<CharT, Traits>
|
||||
{
|
||||
mutable basic_pipebuf<CharT, Traits> _buf;
|
||||
public:
|
||||
|
||||
typedef basic_pipe<CharT, Traits> pipe_type;
|
||||
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
|
||||
///Get access to the underlying stream_buf
|
||||
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
|
||||
|
||||
///Default constructor.
|
||||
basic_ipstream() : std::basic_istream<CharT, Traits>(nullptr)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy constructor.
|
||||
basic_ipstream(const basic_ipstream & ) = delete;
|
||||
///Move constructor.
|
||||
basic_ipstream(basic_ipstream && lhs) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
}
|
||||
|
||||
///Move construct from a pipe.
|
||||
basic_ipstream(pipe_type && p) : std::basic_istream<CharT, Traits>(nullptr), _buf(std::move(p))
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
}
|
||||
|
||||
///Copy construct from a pipe.
|
||||
basic_ipstream(const pipe_type & p) : std::basic_istream<CharT, Traits>(nullptr), _buf(p)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::rdbuf(&_buf);
|
||||
}
|
||||
|
||||
///Copy assignment.
|
||||
basic_ipstream& operator=(const basic_ipstream & ) = delete;
|
||||
///Move assignment
|
||||
basic_ipstream& operator=(basic_ipstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(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)
|
||||
{
|
||||
_buf = std::move(p);
|
||||
return *this;
|
||||
}
|
||||
///Copy assignment of a pipe.
|
||||
basic_ipstream& operator=(const pipe_type & p)
|
||||
{
|
||||
_buf = p;
|
||||
return *this;
|
||||
}
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(const pipe_type& p) {_buf.pipe(p); }
|
||||
///Get a reference to the pipe.
|
||||
pipe_type & pipe() & {return _buf.pipe();}
|
||||
///Get a const reference to the pipe.
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///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();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_ipstream<char> ipstream;
|
||||
typedef basic_ipstream<wchar_t> wipstream;
|
||||
|
||||
/** Implementation of a write pipe stream.
|
||||
*
|
||||
*/
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
class basic_opstream : public std::basic_ostream<CharT, Traits>
|
||||
{
|
||||
mutable basic_pipebuf<CharT, Traits> _buf;
|
||||
public:
|
||||
typedef basic_pipe<CharT, Traits> pipe_type;
|
||||
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
|
||||
|
||||
///Get access to the underlying stream_buf
|
||||
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
|
||||
|
||||
///Default constructor.
|
||||
basic_opstream() : std::basic_ostream<CharT, Traits>(nullptr)
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy constructor.
|
||||
basic_opstream(const basic_opstream & ) = delete;
|
||||
///Move constructor.
|
||||
basic_opstream(basic_opstream && lhs) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
}
|
||||
///Move construct from a pipe.
|
||||
basic_opstream(pipe_type && p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(std::move(p))
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy construct from a pipe.
|
||||
basic_opstream(const pipe_type & p) : std::basic_ostream<CharT, Traits>(nullptr), _buf(p)
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy assignment.
|
||||
basic_opstream& operator=(const basic_opstream & ) = delete;
|
||||
///Move assignment
|
||||
basic_opstream& operator=(basic_opstream && lhs)
|
||||
{
|
||||
std::basic_ostream<CharT, Traits>::operator=(std::move(lhs));
|
||||
_buf = std::move(lhs._buf);
|
||||
std::basic_ostream<CharT, Traits>::rdbuf(&_buf);
|
||||
return *this;
|
||||
};
|
||||
|
||||
///Move assignment of a pipe.
|
||||
basic_opstream& operator=(pipe_type && p)
|
||||
{
|
||||
_buf = std::move(p);
|
||||
return *this;
|
||||
}
|
||||
///Copy assignment of a pipe.
|
||||
basic_opstream& operator=(const pipe_type & p)
|
||||
{
|
||||
_buf = p;
|
||||
return *this;
|
||||
}
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(const pipe_type& p) {_buf.pipe(p); }
|
||||
///Get a reference to the pipe.
|
||||
pipe_type & pipe() & {return _buf.pipe();}
|
||||
///Get a const reference to the pipe.
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_opstream<char> opstream;
|
||||
typedef basic_opstream<wchar_t> wopstream;
|
||||
|
||||
|
||||
/** Implementation of a read-write pipe stream.
|
||||
*
|
||||
*/
|
||||
template<
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>
|
||||
>
|
||||
class basic_pstream : public std::basic_iostream<CharT, Traits>
|
||||
{
|
||||
mutable basic_pipebuf<CharT, Traits> _buf;
|
||||
public:
|
||||
typedef basic_pipe<CharT, Traits> pipe_type;
|
||||
|
||||
typedef CharT char_type ;
|
||||
typedef Traits traits_type;
|
||||
typedef typename Traits::int_type int_type ;
|
||||
typedef typename Traits::pos_type pos_type ;
|
||||
typedef typename Traits::off_type off_type ;
|
||||
|
||||
|
||||
///Get access to the underlying stream_buf
|
||||
basic_pipebuf<CharT, Traits>* rdbuf() const {return &_buf;};
|
||||
|
||||
///Default constructor.
|
||||
basic_pstream() : std::basic_iostream<CharT, Traits>(nullptr)
|
||||
{
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy constructor.
|
||||
basic_pstream(const basic_pstream & ) = delete;
|
||||
///Move constructor.
|
||||
basic_pstream(basic_pstream && lhs) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(lhs._buf))
|
||||
{
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
}
|
||||
///Move construct from a pipe.
|
||||
basic_pstream(pipe_type && p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(std::move(p))
|
||||
{
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy construct from a pipe.
|
||||
basic_pstream(const pipe_type & p) : std::basic_iostream<CharT, Traits>(nullptr), _buf(p)
|
||||
{
|
||||
std::basic_iostream<CharT, Traits>::rdbuf(&_buf);
|
||||
};
|
||||
///Copy assignment.
|
||||
basic_pstream& operator=(const basic_pstream & ) = delete;
|
||||
///Move assignment
|
||||
basic_pstream& operator=(basic_pstream && lhs)
|
||||
{
|
||||
std::basic_istream<CharT, Traits>::operator=(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)
|
||||
{
|
||||
_buf = std::move(p);
|
||||
return *this;
|
||||
}
|
||||
///Copy assignment of a pipe.
|
||||
basic_pstream& operator=(const pipe_type & p)
|
||||
{
|
||||
_buf = p;
|
||||
return *this;
|
||||
}
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(pipe_type&& p) {_buf.pipe(std::move(p)); }
|
||||
///Set the pipe of the streambuf.
|
||||
void pipe(const pipe_type& p) {_buf.pipe(p); }
|
||||
///Get a reference to the pipe.
|
||||
pipe_type & pipe() & {return _buf.pipe();}
|
||||
///Get a const reference to the pipe.
|
||||
const pipe_type &pipe() const & {return _buf.pipe();}
|
||||
///Get a rvalue reference to the pipe. Qualified as rvalue.
|
||||
pipe_type && pipe() && {return std::move(_buf).pipe();}
|
||||
|
||||
///Open a new pipe
|
||||
void open()
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Open a new named pipe
|
||||
void open(const std::string & name)
|
||||
{
|
||||
if (_buf.open() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
///Flush the buffer & close the pipe
|
||||
void close()
|
||||
{
|
||||
if (_buf.close() == nullptr)
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_pstream<char> pstream;
|
||||
typedef basic_pstream<wchar_t> wpstream;
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/pipe.hpp>")
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
|
||||
@@ -1,75 +1,9 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_PROCESS_POSIX_HPP_
|
||||
#define BOOST_PROCESS_POSIX_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/fd.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/use_vfork.hpp>
|
||||
#include <boost/process/detail/posix/signal.hpp>
|
||||
|
||||
|
||||
/** \file boost/process/posix.hpp
|
||||
*
|
||||
* Header which provides the posix extensions.
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace posix {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::fd">fd</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::sig">sig</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::posix::use_vfork">use_vfork</globalname>;
|
||||
}
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
* \endxmlonly
|
||||
* \warning Only available on posix. See the documentation of [fork](http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html),
|
||||
* [execve](http://pubs.opengroup.org/onlinepubs/009695399/functions/execve.html) and
|
||||
* [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html).
|
||||
*
|
||||
*/
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
///Namespace containing the posix exensions.
|
||||
namespace posix {
|
||||
|
||||
/** This property lets you modify file-descriptors other than the standard ones (0,1,2).
|
||||
*
|
||||
* It provides the functions `bind`, which implements [dup2](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)
|
||||
* and [close](http://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
|
||||
*
|
||||
* Close can also be called with a range of file-descriptors to be closed.
|
||||
*
|
||||
*/
|
||||
constexpr ::boost::process::detail::posix::fd_ fd;
|
||||
|
||||
/** This property lets you modify the handling of `SIGCHLD` for this call. It will be reset afterwards.
|
||||
|
||||
It can be set to default, by the expression `sig.dfl()`, set to ignore with `sig.ign()` or
|
||||
assigned a custom handler. A custom handler must have the type `sighandler_t`and can be assigned with the following syntax:
|
||||
|
||||
\code{.cpp}
|
||||
sig = handler;
|
||||
sig(handler);
|
||||
\endcode
|
||||
|
||||
\warning @ref spawn will automatically use `sig.ign()`, which will override if you pass a custom handler.
|
||||
*/
|
||||
constexpr ::boost::process::detail::posix::sig_ sig;
|
||||
/** This property will replace the usage of [fork](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html) by [vfork](http://pubs.opengroup.org/onlinepubs/009695399/functions/vfork.html).
|
||||
\note `vfork` is no longer an official part of the posix standard.
|
||||
|
||||
*/
|
||||
constexpr ::boost::process::detail::posix::use_vfork_ use_vfork;
|
||||
|
||||
|
||||
using ::boost::process::detail::posix::sighandler_t;
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_POSIX_HPP_ */
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/posix.hpp>")
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
|
||||
@@ -1,54 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/search_path.hpp
|
||||
*
|
||||
* Defines a function to search for an executable in path.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_SEARCH_PATH_HPP
|
||||
#define BOOST_PROCESS_SEARCH_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/search_path.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/search_path.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process {
|
||||
|
||||
/**
|
||||
* Searches for an executable in path.
|
||||
*
|
||||
* filename must be a basename including the file extension.
|
||||
* It must not include any directory separators (like a slash).
|
||||
* On Windows the file extension may be omitted. The function
|
||||
* will then try the various file extensions for executables on
|
||||
* Windows to find filename.
|
||||
*
|
||||
* \param filename The base of the filename to find
|
||||
*
|
||||
* \param path the set of paths to search, defaults to the "PATH" environment variable.
|
||||
*
|
||||
* \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())
|
||||
{
|
||||
return ::boost::process::detail::api::search_path(filename, path);
|
||||
}
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/search_path.hpp>")
|
||||
#include <boost/process/v1/search_path.hpp>
|
||||
|
||||
@@ -1,92 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_SHELL_PATH_HPP
|
||||
#define BOOST_PROCESS_SHELL_PATH_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/shell_path.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/shell_path.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/shell.hpp
|
||||
*
|
||||
* Header which provides the shell property. This provides the
|
||||
* property to launch a process through the system shell.
|
||||
* It also allows the user to obtain the shell-path via shell().
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::shell">shell</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
|
||||
struct shell_
|
||||
{
|
||||
constexpr shell_() {}
|
||||
|
||||
boost::filesystem::path operator()() const
|
||||
{
|
||||
return boost::process::detail::api::shell_path();
|
||||
}
|
||||
boost::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>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
/**
|
||||
The shell property enables to launch a program through the shell of the system.
|
||||
|
||||
\code{.cpp}
|
||||
system("gcc", shell);
|
||||
\endcode
|
||||
|
||||
The shell argument goes without any expression. The operator() is overloaded, to
|
||||
obtain the path of the system shell.
|
||||
|
||||
\code{.cpp}
|
||||
auto shell_cmd = shell();
|
||||
//avoid exceptions
|
||||
std::error_code ec;
|
||||
shell_cmd = shell(ec);
|
||||
\endcode
|
||||
|
||||
\attention Launching through the shell will NOT provide proper error handling, i.e.
|
||||
you will get an error via the return code.
|
||||
|
||||
\attention Executing shell commands that incorporate unsanitized input from an untrusted source makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of `shell` is strongly discouraged in cases where the command string is constructed from external input:
|
||||
|
||||
*/
|
||||
constexpr ::boost::process::detail::shell_ shell;
|
||||
|
||||
}}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/shell.hpp>")
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
|
||||
@@ -1,69 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/spawn.hpp
|
||||
*
|
||||
* Defines the spawn function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_SPAWN_HPP
|
||||
#define BOOST_PROCESS_SPAWN_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
#include <boost/process/detail/async_handler.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail {
|
||||
|
||||
}
|
||||
|
||||
/** Launch a process and detach it. Returns no handle.
|
||||
|
||||
This function starts a process and immediately detaches it. It thereby prevents the system from creating a zombie process,
|
||||
but will also cause the system to be unable to wait for the child to exit.
|
||||
|
||||
\note This will set `SIGCHLD` to `SIGIGN` on posix.
|
||||
|
||||
\warning This function does not allow asynchronous operations, since it cannot wait for the end of the process.
|
||||
It will fail to compile if a reference to `boost::asio::io_context` is passed.
|
||||
|
||||
*/
|
||||
template<typename ...Args>
|
||||
inline void spawn(Args && ...args)
|
||||
{
|
||||
typedef typename ::boost::process::detail::has_async_handler<Args...>::type
|
||||
has_async;
|
||||
|
||||
|
||||
static_assert(
|
||||
!has_async::value,
|
||||
"Spawn cannot wait for exit, so async properties cannot be used");
|
||||
|
||||
auto c = ::boost::process::detail::execute_impl(
|
||||
#if defined(BOOST_POSIX_API)
|
||||
::boost::process::posix::sig.ign(),
|
||||
#endif
|
||||
std::forward<Args>(args)...);
|
||||
c.detach();
|
||||
}
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/spawn.hpp>")
|
||||
#include <boost/process/v1/spawn.hpp>
|
||||
|
||||
@@ -1,111 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_START_IN_DIR_HPP
|
||||
#define BOOST_PROCESS_START_IN_DIR_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
#include <boost/process/locale.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined (BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/start_dir.hpp>
|
||||
#elif defined (BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/start_dir.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
/** \file boost/process/start_dir.hpp
|
||||
*
|
||||
Header which provides the start_dir property, which allows to set the directory
|
||||
the process shall be started in.
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::start_dir">start_dir</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
|
||||
struct start_dir_
|
||||
{
|
||||
constexpr start_dir_() {};
|
||||
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator()(const std::basic_string<Char> & st) const {return {st}; }
|
||||
template<typename Char>
|
||||
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()}; }
|
||||
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; }
|
||||
template<typename Char>
|
||||
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()}; }
|
||||
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<api::start_dir_init<wchar_t>> : std::true_type {};
|
||||
|
||||
template<>
|
||||
struct char_converter<char, api::start_dir_init<wchar_t>>
|
||||
{
|
||||
static api::start_dir_init<char> conv(const api::start_dir_init<wchar_t> & in)
|
||||
{
|
||||
return api::start_dir_init<char>{::boost::process::detail::convert(in.str())};
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, api::start_dir_init<char>>
|
||||
{
|
||||
static api::start_dir_init<wchar_t> conv(const api::start_dir_init<char> & in)
|
||||
{
|
||||
return api::start_dir_init<wchar_t>{::boost::process::detail::convert(in.str())};
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
To set the start dir, the `start_dir` property is provided.
|
||||
|
||||
The valid operations are the following:
|
||||
|
||||
\code{.cpp}
|
||||
start_dir=path
|
||||
start_dir(path)
|
||||
\endcode
|
||||
|
||||
It can be used with `std::string`, `std::wstring` and `boost::filesystem::path`.
|
||||
|
||||
|
||||
*/
|
||||
constexpr ::boost::process::detail::start_dir_ start_dir;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/start_dir.hpp>")
|
||||
#include <boost/process/v1/start_dir.hpp>
|
||||
|
||||
@@ -1,157 +1,9 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/system.hpp
|
||||
*
|
||||
* Defines a system function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_SYSTEM_HPP
|
||||
#define BOOST_PROCESS_SYSTEM_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/on_exit.hpp>
|
||||
#include <boost/process/child.hpp>
|
||||
#include <boost/process/detail/async_handler.hpp>
|
||||
#include <boost/process/detail/execute_impl.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <type_traits>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct system_impl_success_check : handler
|
||||
{
|
||||
bool succeeded = false;
|
||||
|
||||
template<typename Exec>
|
||||
void on_success(Exec &) { succeeded = true; }
|
||||
};
|
||||
|
||||
template<typename IoService, typename ...Args>
|
||||
inline int system_impl(
|
||||
std::true_type, /*needs ios*/
|
||||
std::true_type, /*has io_context*/
|
||||
Args && ...args)
|
||||
{
|
||||
IoService & ios = ::boost::process::detail::get_io_context_var(args...);
|
||||
|
||||
system_impl_success_check check;
|
||||
|
||||
std::atomic_bool exited{false};
|
||||
|
||||
child c(std::forward<Args>(args)...,
|
||||
check,
|
||||
::boost::process::on_exit(
|
||||
[&](int, const std::error_code&)
|
||||
{
|
||||
boost::asio::post(ios.get_executor(), [&]{exited.store(true);});
|
||||
}));
|
||||
if (!c.valid() || !check.succeeded)
|
||||
return -1;
|
||||
|
||||
while (!exited.load())
|
||||
ios.poll();
|
||||
|
||||
return c.exit_code();
|
||||
}
|
||||
|
||||
template<typename IoService, typename ...Args>
|
||||
inline int system_impl(
|
||||
std::true_type, /*needs ios */
|
||||
std::false_type, /*has io_context*/
|
||||
Args && ...args)
|
||||
{
|
||||
IoService ios;
|
||||
child c(ios, std::forward<Args>(args)...);
|
||||
if (!c.valid())
|
||||
return -1;
|
||||
|
||||
ios.run();
|
||||
if (c.running())
|
||||
c.wait();
|
||||
return c.exit_code();
|
||||
}
|
||||
|
||||
|
||||
template<typename IoService, typename ...Args>
|
||||
inline int system_impl(
|
||||
std::false_type, /*needs ios*/
|
||||
std::true_type, /*has io_context*/
|
||||
Args && ...args)
|
||||
{
|
||||
child c(std::forward<Args>(args)...);
|
||||
if (!c.valid())
|
||||
return -1;
|
||||
c.wait();
|
||||
return c.exit_code();
|
||||
}
|
||||
|
||||
template<typename IoService, typename ...Args>
|
||||
inline int system_impl(
|
||||
std::false_type, /*has async */
|
||||
std::false_type, /*has io_context*/
|
||||
Args && ...args)
|
||||
{
|
||||
child c(std::forward<Args>(args)...
|
||||
#if defined(BOOST_POSIX_API)
|
||||
,::boost::process::posix::sig.dfl()
|
||||
#endif
|
||||
);
|
||||
if (!c.valid())
|
||||
return -1;
|
||||
c.wait();
|
||||
return c.exit_code();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Launches a process and waits for its exit.
|
||||
It works as std::system, though it allows
|
||||
all the properties boost.process provides. It will execute the process and wait for it's exit; then return the exit_code.
|
||||
|
||||
\code{.cpp}
|
||||
int ret = system("ls");
|
||||
\endcode
|
||||
|
||||
\attention Using this function with synchronous pipes leads to many potential deadlocks.
|
||||
|
||||
When using this function with an asynchronous properties and NOT passing an io_context object,
|
||||
the system function will create one and run it. When the io_context is passed to the function,
|
||||
the system function will check if it is active, and call the io_context::run function if not.
|
||||
|
||||
*/
|
||||
template<typename ...Args>
|
||||
inline int system(Args && ...args)
|
||||
{
|
||||
typedef typename ::boost::process::detail::needs_io_context<Args...>::type
|
||||
need_ios;
|
||||
typedef typename ::boost::process::detail::has_io_context<Args...>::type
|
||||
has_ios;
|
||||
return ::boost::process::detail::system_impl<boost::asio::io_context>(
|
||||
need_ios(), has_ios(),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/system.hpp>")
|
||||
#include <boost/process/v1/system.hpp>
|
||||
|
||||
28
include/boost/process/v1.hpp
Normal file
28
include/boost/process/v1.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2024 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#ifndef BOOST_PROCESS_V1_HPP
|
||||
#define BOOST_PROCESS_V1_HPP
|
||||
|
||||
#include <boost/process/v1/args.hpp>
|
||||
#include <boost/process/v1/async.hpp>
|
||||
#include <boost/process/v1/async_system.hpp>
|
||||
#include <boost/process/v1/group.hpp>
|
||||
#include <boost/process/v1/child.hpp>
|
||||
#include <boost/process/v1/cmd.hpp>
|
||||
#include <boost/process/v1/env.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/process/v1/exe.hpp>
|
||||
#include <boost/process/v1/group.hpp>
|
||||
#include <boost/process/v1/handles.hpp>
|
||||
#include <boost/process/v1/io.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
#include <boost/process/v1/search_path.hpp>
|
||||
#include <boost/process/v1/spawn.hpp>
|
||||
#include <boost/process/v1/system.hpp>
|
||||
#include <boost/process/v1/start_dir.hpp>
|
||||
|
||||
#endif //BOOST_PROCESS_V1_HPP
|
||||
279
include/boost/process/v1/args.hpp
Normal file
279
include/boost/process/v1/args.hpp
Normal file
@@ -0,0 +1,279 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_ARGS_HPP
|
||||
#define BOOST_PROCESS_ARGS_HPP
|
||||
|
||||
/** \file boost/process/args.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::v1::args">args</globalname>\endxmlonly property. It also provides the
|
||||
* alternative name \xmlonly <globalname alt="boost::process::v1::argv">argv</globalname>\endxmlonly .
|
||||
*
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::args">args</globalname>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::argv">argv</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
|
||||
#include <boost/process/v1/detail/basic_cmd.hpp>
|
||||
#include <iterator>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct args_
|
||||
{
|
||||
template<typename T>
|
||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||
template<typename T>
|
||||
using value_type = typename remove_reference_t<T>::value_type;
|
||||
|
||||
template<typename T>
|
||||
using vvalue_type = value_type<value_type<T>>;
|
||||
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator()(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, true> operator+=(Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, true>(std::forward<Range>(range));
|
||||
}
|
||||
template <class Range>
|
||||
arg_setter_<vvalue_type<Range>, false> operator= (Range &&range) const
|
||||
{
|
||||
return arg_setter_<vvalue_type<Range>, false>(std::forward<Range>(range));
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> && str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (std::basic_string<Char> & str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator()(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, true> operator+=(const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, true> (str);
|
||||
}
|
||||
template<typename Char>
|
||||
arg_setter_<Char, false> operator= (const Char* str) const
|
||||
{
|
||||
return arg_setter_<Char, false>(str);
|
||||
}
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator()(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, true> operator+=(const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, true> (str);
|
||||
// }
|
||||
// template<typename Char, std::size_t Size>
|
||||
// arg_setter_<Char, false> operator= (const Char (&str) [Size]) const
|
||||
// {
|
||||
// return arg_setter_<Char, false>(str);
|
||||
// }
|
||||
|
||||
arg_setter_<char, true> operator()(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<const char*> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, true> operator+=(std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
return arg_setter_<char, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<char, false> operator= (std::initializer_list<std::string> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<const wchar_t*> &&range) const
|
||||
{
|
||||
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, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, true> operator+=(std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, true>(range.begin(), range.end());
|
||||
}
|
||||
arg_setter_<wchar_t, false> operator= (std::initializer_list<std::wstring> &&range) const
|
||||
{
|
||||
return arg_setter_<wchar_t, false>(range.begin(), range.end());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
/**
|
||||
|
||||
The `args` property allows to explicitly set arguments for the execution. The
|
||||
name of the executable will always be the first element in the arg-vector.
|
||||
|
||||
\section args_details Details
|
||||
|
||||
\subsection args_operations Operations
|
||||
|
||||
\subsubsection args_set_var Setting values
|
||||
|
||||
To set a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args = value;
|
||||
args(value);
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args = {value1, value2};
|
||||
args({value1, value2});
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_set_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
\subsubsection args_append_var Appending values
|
||||
|
||||
To append a the argument vector the following syntax can be used.
|
||||
|
||||
\code{.cpp}
|
||||
args += value;
|
||||
\endcode
|
||||
|
||||
`std::initializer_list` is among the allowed types, so the following syntax is also possible.
|
||||
|
||||
\code{.cpp}
|
||||
args += {value1, value2};
|
||||
\endcode
|
||||
|
||||
Below the possible types for `value` are listed, with `char_type` being either `char` or `wchar_t`.
|
||||
|
||||
\paragraph args_append_var_value value
|
||||
|
||||
- `std::basic_string<char_type>`
|
||||
- `const char_type * `
|
||||
- `std::initializer_list<const char_type *>`
|
||||
- `std::vector<std::basic_string<char_type>>`
|
||||
|
||||
Additionally any range of `std::basic_string<char_type>` can be passed.
|
||||
|
||||
|
||||
\subsection args_example Example
|
||||
|
||||
The overload form is used when more than one string is passed, from the second one forward.
|
||||
I.e. the following expressions have the same results:
|
||||
|
||||
\code{.cpp}
|
||||
spawn("gcc", "--version");
|
||||
spawn("gcc", args ="--version");
|
||||
spawn("gcc", args+="--version");
|
||||
spawn("gcc", args ={"--version"});
|
||||
spawn("gcc", args+={"--version"});
|
||||
\endcode
|
||||
|
||||
\note A string will be parsed and set in quotes if it has none and contains spaces.
|
||||
|
||||
|
||||
*/
|
||||
constexpr boost::process::v1::detail::args_ args{};
|
||||
|
||||
///Alias for \xmlonly <globalname alt="boost::process::v1::args">args</globalname> \endxmlonly .
|
||||
constexpr boost::process::v1::detail::args_ argv{};
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
134
include/boost/process/v1/async.hpp
Normal file
134
include/boost/process/v1/async.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/** \file boost/process/async.hpp
|
||||
|
||||
The header which provides the basic asynchronous features.
|
||||
It provides the on_exit property, which allows callbacks when the process exits.
|
||||
It also implements the necessary traits for passing an boost::asio::io_context,
|
||||
which is needed for asynchronous communication.
|
||||
|
||||
It also pulls the [boost::asio::buffer](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/buffer.html)
|
||||
into the boost::process namespace for convenience.
|
||||
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process {
|
||||
namespace v1 {
|
||||
<emphasis>unspecified</emphasis> <ulink url="http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/buffer.html">buffer</ulink>;
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::on_exit">on_exit</globalname>;
|
||||
}
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_HPP_
|
||||
#define BOOST_PROCESS_ASYNC_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/traits.hpp>
|
||||
#include <boost/process/v1/detail/on_exit.hpp>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/fusion/iterator/deref.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/io_context_ref.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_in.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_out.hpp>
|
||||
#include <boost/process/v1/detail/posix/on_exit.hpp>
|
||||
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/io_context_ref.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_in.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_out.hpp>
|
||||
#include <boost/process/v1/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
struct async_tag;
|
||||
|
||||
template<typename T>
|
||||
struct is_io_context : std::false_type {};
|
||||
template<>
|
||||
struct is_io_context<api::io_context_ref> : std::true_type {};
|
||||
|
||||
template<typename Tuple>
|
||||
inline asio::io_context& get_io_context(const Tuple & tup)
|
||||
{
|
||||
auto& ref = *boost::fusion::find_if<is_io_context<boost::mpl::_>>(tup);
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
struct async_builder
|
||||
{
|
||||
boost::asio::io_context * ios;
|
||||
|
||||
void operator()(boost::asio::io_context & ios_) {this->ios = &ios_;};
|
||||
|
||||
typedef api::io_context_ref result_type;
|
||||
api::io_context_ref get_initializer() {return api::io_context_ref (*ios);};
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct initializer_builder<async_tag>
|
||||
{
|
||||
typedef async_builder type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using ::boost::asio::buffer;
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** When an io_context is passed, the on_exit property can be used, to be notified
|
||||
when the child process exits.
|
||||
|
||||
|
||||
The following syntax is valid
|
||||
|
||||
\code{.cpp}
|
||||
on_exit=function;
|
||||
on_exit(function);
|
||||
\endcode
|
||||
|
||||
with `function` being a callable object with the signature `(int, const std::error_code&)` or an
|
||||
`std::future<int>`.
|
||||
|
||||
\par Example
|
||||
|
||||
\code{.cpp}
|
||||
io_context ios;
|
||||
|
||||
child c("ls", ios, on_exit=[](int exit, const std::error_code& ec_in){});
|
||||
|
||||
std::future<int> exit_code;
|
||||
chlid c2("ls", ios, on_exit=exit_code);
|
||||
|
||||
\endcode
|
||||
|
||||
\note The handler is not invoked when the launch fails.
|
||||
\warning When used \ref ignore_error it might get invoked on error.
|
||||
\warning `on_exit` uses `boost::asio::signal_set` to listen for `SIGCHLD` on posix, and so has the
|
||||
same restrictions as that class (do not register a handler for `SIGCHLD` except by using
|
||||
`boost::asio::signal_set`).
|
||||
*/
|
||||
constexpr static ::boost::process::v1::detail::on_exit_ on_exit{};
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_DETAIL_ASYNC_HPP_ */
|
||||
217
include/boost/process/v1/async_pipe.hpp
Normal file
217
include/boost/process/v1/async_pipe.hpp
Normal file
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
#define BOOST_PROCESS_ASYNC_PIPE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/async_pipe.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/async_pipe.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
|
||||
|
||||
/** 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.
|
||||
*
|
||||
* It can be used directly with boost::asio::async_read or async_write.
|
||||
*
|
||||
* \note The object is copyable, but that does invoke a handle duplicate.
|
||||
*/
|
||||
class async_pipe
|
||||
{
|
||||
public:
|
||||
/** Typedef for the native handle representation.
|
||||
* \note This is the handle on the system, not the boost.asio class.
|
||||
*
|
||||
*/
|
||||
typedef platform_specific native_handle_type;
|
||||
/** Typedef for the handle representation of boost.asio.
|
||||
*
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open the pipe.
|
||||
* @note Windows creates a named pipe here, where the name is automatically generated.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink);
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
* Initializes source and sink with the same io_context.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios, const std::string & name);
|
||||
|
||||
|
||||
/** Construct a new async_pipe, does automatically open.
|
||||
*
|
||||
* @note Windows restricts possible names.
|
||||
*/
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink, const std::string & name);
|
||||
|
||||
/** Copy-Constructor of the async pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
async_pipe(const async_pipe& lhs);
|
||||
|
||||
/** Move-Constructor of the async pipe.
|
||||
*/
|
||||
async_pipe(async_pipe&& lhs);
|
||||
|
||||
/** Construct the async-pipe from a pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios, const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
/** Construct the async-pipe from a pipe, with two different io_context objects.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
explicit async_pipe(boost::asio::io_context & ios_source,
|
||||
boost::asio::io_context & ios_sink,
|
||||
const basic_pipe<CharT, Traits> & p);
|
||||
|
||||
|
||||
/** Assign a basic_pipe.
|
||||
* @note Windows requires a named pipe for this, if a the wrong type is used an exception is thrown.
|
||||
*
|
||||
*/
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline async_pipe& operator=(const basic_pipe<CharT, Traits>& p);
|
||||
|
||||
/** Copy Assign a pipe.
|
||||
* @note Duplicates the handles.
|
||||
*/
|
||||
async_pipe& operator=(const async_pipe& lhs);
|
||||
/** Move assign a pipe */
|
||||
async_pipe& operator=(async_pipe&& lhs);
|
||||
|
||||
/** Destructor. Closes the pipe handles. */
|
||||
~async_pipe();
|
||||
|
||||
/** Explicit cast to basic_pipe. */
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
inline explicit operator basic_pipe<CharT, Traits>() const;
|
||||
|
||||
/** Cancel the current asynchronous operations. */
|
||||
void cancel();
|
||||
/** Close the pipe handles. */
|
||||
void close();
|
||||
/** Close the pipe handles. While passing an error_code
|
||||
*
|
||||
*/
|
||||
void close(std::error_code & ec);
|
||||
|
||||
/** Check if the pipes are open. */
|
||||
bool is_open() const;
|
||||
|
||||
/** Async close, i.e. close after current operation is completed.
|
||||
*
|
||||
* \note There is no guarantee that this will indeed read the entire pipe-buffer
|
||||
*/
|
||||
void async_close();
|
||||
|
||||
/** Read some data from the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t read_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Write some data to the handle.
|
||||
|
||||
* See the boost.asio documentation for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence>
|
||||
std::size_t write_some(const MutableBufferSequence & buffers);
|
||||
|
||||
/** Get the native handle of the source. */
|
||||
native_handle native_source() const {return const_cast<boost::asio::windows::stream_handle&>(_source).native();}
|
||||
/** Get the native handle of the sink. */
|
||||
native_handle native_sink () const {return const_cast<boost::asio::windows::stream_handle&>(_sink ).native();}
|
||||
|
||||
/** Start an asynchronous read.
|
||||
*
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html) for more details.
|
||||
*/
|
||||
template<typename MutableBufferSequence,
|
||||
typename ReadHandler>
|
||||
detail::dummy async_read_some(
|
||||
const MutableBufferSequence & buffers,
|
||||
ReadHandler &&handler);
|
||||
|
||||
/** Start an asynchronous write.
|
||||
|
||||
* See the [boost.asio documentation](http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html) for more details.
|
||||
*/
|
||||
template<typename ConstBufferSequence,
|
||||
typename WriteHandler>
|
||||
detail::dummy async_write_some(
|
||||
const ConstBufferSequence & buffers,
|
||||
WriteHandler && handler);
|
||||
|
||||
///Get the asio handle of the pipe sink.
|
||||
const handle_type & sink () const &;
|
||||
///Get the asio handle of the pipe source.
|
||||
const handle_type & source() const &;
|
||||
|
||||
///Get the asio handle of the pipe sink. Qualified as rvalue
|
||||
handle_type && sink () &&;
|
||||
///Get the asio handle of the pipe source. Qualified as rvalue
|
||||
handle_type && source() &&;
|
||||
|
||||
/// Move the source out of this class and change the io_context. Qualified as rvalue. \attention Will always move.
|
||||
handle_type source(::boost::asio::io_context& ios) &&;
|
||||
/// Move the sink out of this class and change the io_context. Qualified as rvalue. \attention Will always move
|
||||
handle_type sink (::boost::asio::io_context& ios) &&;
|
||||
|
||||
/// Copy the source out of this class and change the io_context. \attention Will always copy.
|
||||
handle_type source(::boost::asio::io_context& ios) const &;
|
||||
/// Copy the sink out of this class and change the io_context. \attention Will always copy
|
||||
handle_type sink (::boost::asio::io_context& ios) const &;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
using ::boost::process::v1::detail::api::async_pipe;
|
||||
#endif
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
151
include/boost/process/v1/async_system.hpp
Normal file
151
include/boost/process/v1/async_system.hpp
Normal file
@@ -0,0 +1,151 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/async_system.hpp
|
||||
*
|
||||
* Defines the asynchronous version of the system function.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
#define BOOST_PROCESS_ASYNC_SYSTEM_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/async.hpp>
|
||||
#include <boost/process/v1/child.hpp>
|
||||
#include <boost/process/v1/detail/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/execute_impl.hpp>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <boost/asio/async_result.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <tuple>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename Handler>
|
||||
struct async_system_handler : ::boost::process::v1::detail::api::async_handler
|
||||
{
|
||||
boost::asio::io_context & ios;
|
||||
Handler handler;
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
bool errored = false;
|
||||
#endif
|
||||
|
||||
template<typename ExitHandler_>
|
||||
async_system_handler(
|
||||
boost::asio::io_context & ios,
|
||||
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
template<typename Exec>
|
||||
void on_error(Exec&, const std::error_code & ec)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
errored = true;
|
||||
#endif
|
||||
auto h = 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);
|
||||
});
|
||||
}
|
||||
|
||||
template<typename Executor>
|
||||
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
|
||||
{
|
||||
#if defined(BOOST_POSIX_API)
|
||||
if (errored)
|
||||
return [](int , const std::error_code &){};
|
||||
#endif
|
||||
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);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename ExitHandler>
|
||||
struct is_error_handler<async_system_handler<ExitHandler>> : std::true_type {};
|
||||
|
||||
}
|
||||
|
||||
/** This function provides an asynchronous interface to process launching.
|
||||
|
||||
It uses the same properties and parameters as the other launching function,
|
||||
but is similar to the asynchronous functions in [boost.asio](http://www.boost.org/doc/libs/release/doc/html/boost_asio.html)
|
||||
|
||||
It uses [asio::async_result](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference/async_result.html) to determine
|
||||
the return value (from the second parameter, `exit_handler`).
|
||||
|
||||
\param ios A reference to an [io_context](http://www.boost.org/doc/libs/release/doc/html/boost_asio/reference.html)
|
||||
\param exit_handler The exit-handler for the signature `void(boost::system::error_code, int)`
|
||||
|
||||
\note This function does not allow custom error handling, since those are done through the `exit_handler`.
|
||||
|
||||
*/
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
template<typename ExitHandler, typename ...Args>
|
||||
inline boost::process::v1::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)
|
||||
{
|
||||
|
||||
typedef typename ::boost::process::v1::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");
|
||||
|
||||
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
|
||||
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
154
include/boost/process/v1/child.hpp
Normal file
154
include/boost/process/v1/child.hpp
Normal file
@@ -0,0 +1,154 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
/**
|
||||
* \file boost/process/child.hpp
|
||||
*
|
||||
* Defines a child process class.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_PROCESS_CHILD_HPP
|
||||
#define BOOST_PROCESS_CHILD_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/detail/execute_impl.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
///The main namespace of boost.process.
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
template<typename ...Args>
|
||||
child::child(Args&&...args)
|
||||
: child(::boost::process::v1::detail::execute_impl(std::forward<Args>(args)...)) {}
|
||||
|
||||
|
||||
///Typedef for the type of an pid_t
|
||||
typedef ::boost::process::v1::detail::api::pid_t pid_t;
|
||||
|
||||
#if defined(BOOST_PROCESS_DOXYGEN)
|
||||
/** The main class to hold a child process. It is simliar to [std::thread](http://en.cppreference.com/w/cpp/thread/thread),
|
||||
* in that it has a join and detach function.
|
||||
*
|
||||
* @attention The destructor will call terminate on the process if not joined or detached without any warning.
|
||||
*
|
||||
*/
|
||||
|
||||
class child
|
||||
{
|
||||
/** Type definition for the native process handle. */
|
||||
typedef platform_specific native_handle_t;
|
||||
|
||||
/** Construct the child from a pid.
|
||||
*
|
||||
* @attention There is no guarantee that this will work. The process need the right access rights, which are very platform specific.
|
||||
*/
|
||||
explicit child(pid_t & pid) : _child_handle(pid) {};
|
||||
|
||||
/** Move-Constructor.*/
|
||||
child(child && lhs);
|
||||
|
||||
/** Construct a child from a property list and launch it
|
||||
* The standard version is to create a subprocess, which will spawn the process.
|
||||
*/
|
||||
template<typename ...Args>
|
||||
explicit child(Args&&...args);
|
||||
|
||||
/** Construct an empty child. */
|
||||
child() = default;
|
||||
|
||||
/** Move assign. */
|
||||
child& operator=(child && lhs);
|
||||
|
||||
/** Detach the child, i.e. let it run after this handle dies. */
|
||||
void detach();
|
||||
/** Join the child. This just calls wait, but that way the naming is similar to std::thread */
|
||||
void join();
|
||||
/** Check if the child is joinable. */
|
||||
bool joinable();
|
||||
|
||||
/** Destructor.
|
||||
* @attention Will call terminate (without warning) when the child was neither joined nor detached.
|
||||
*/
|
||||
~child();
|
||||
|
||||
/** Get the native handle for the child process. */
|
||||
native_handle_t native_handle() const;
|
||||
|
||||
/** Get the exit_code. The return value is without any meaning if the child wasn't waited for or if it was terminated. */
|
||||
int exit_code() const;
|
||||
/** Get the Process Identifier. */
|
||||
pid_t id() const;
|
||||
|
||||
/** Get the native, uninterpreted exit code. The return value is without any meaning if the child wasn't waited
|
||||
* for or if it was terminated. */
|
||||
int native_exit_code() const;
|
||||
|
||||
/** Check if the child process is running. */
|
||||
bool running();
|
||||
/** \overload void running() */
|
||||
bool running(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit. */
|
||||
void wait();
|
||||
/** \overload void wait() */
|
||||
void wait(std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit for a period of time.
|
||||
* \return True if child exited while waiting.
|
||||
*/
|
||||
template< class Rep, class Period >
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time);
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) */
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Wait for the child process to exit until a point in time.
|
||||
* \return True if child exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time );
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )*/
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept;
|
||||
|
||||
/** Check if this handle holds a child process.
|
||||
* @note That does not mean, that the process is still running. It only means, that the handle does or did exist.
|
||||
*/
|
||||
bool valid() const;
|
||||
/** Same as valid, for convenience. */
|
||||
explicit operator bool() const;
|
||||
|
||||
/** Check if the the chlid process is in any process group. */
|
||||
bool in_group() const;
|
||||
|
||||
/** \overload bool in_group() const */
|
||||
bool in_group(std::error_code & ec) const noexcept;
|
||||
|
||||
/** Terminate the child process.
|
||||
*
|
||||
* This function will cause the child process to unconditionally and immediately exit.
|
||||
* It is implement with [SIGKILL](http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.html) on posix
|
||||
* and [TerminateProcess](https://technet.microsoft.com/en-us/library/ms686714.aspx) on windows.
|
||||
*
|
||||
*/
|
||||
void terminate();
|
||||
|
||||
/** \overload void terminate() */
|
||||
void terminate(std::error_code & ec) noexcept;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
#endif
|
||||
|
||||
121
include/boost/process/v1/cmd.hpp
Normal file
121
include/boost/process/v1/cmd.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
|
||||
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
|
||||
// Copyright (c) 2009 Boris Schaeling
|
||||
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
|
||||
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
|
||||
// Copyright (c) 2016 Klemens D. Morgenstern
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_CMD_LINE_HPP
|
||||
|
||||
#include <boost/winapi/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/v1/detail/windows/cmd.hpp>
|
||||
#endif
|
||||
|
||||
/** \file boost/process/cmd.hpp
|
||||
*
|
||||
* This header provides the \xmlonly <globalname alt="boost::process::v1::cmd">cmd</globalname>\endxmlonly property.
|
||||
*
|
||||
\xmlonly
|
||||
<programlisting>
|
||||
namespace boost {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
<emphasis>unspecified</emphasis> <globalname alt="boost::process::v1::cmd">cmd</globalname>;
|
||||
}
|
||||
}
|
||||
</programlisting>
|
||||
\endxmlonly
|
||||
*/
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
|
||||
struct cmd_
|
||||
{
|
||||
constexpr cmd_() = default;
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const Char *s) const
|
||||
{ return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const Char *s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator()(const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
template<typename Char>
|
||||
inline api::cmd_setter_<Char> operator= (const std::basic_string<Char> &s) const
|
||||
{
|
||||
return api::cmd_setter_<Char>(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct is_wchar_t<api::cmd_setter_<wchar_t>> : std::true_type {};
|
||||
|
||||
|
||||
|
||||
template<>
|
||||
struct char_converter<char, api::cmd_setter_<wchar_t>>
|
||||
{
|
||||
static api::cmd_setter_<char> conv(const api::cmd_setter_<wchar_t> & in)
|
||||
{
|
||||
return { ::boost::process::v1::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct char_converter<wchar_t, api::cmd_setter_<char>>
|
||||
{
|
||||
static api::cmd_setter_<wchar_t> conv(const api::cmd_setter_<char> & in)
|
||||
{
|
||||
return { ::boost::process::v1::detail::convert(in.str()) };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The cmd property allows to explicitly set commands for the execution.
|
||||
|
||||
The overload form applies when only one string is passed to a launching function.
|
||||
The string will be internally parsed and split at spaces.
|
||||
|
||||
The following expressions are valid, with `value` being either a C-String or
|
||||
a `std::basic_string` with `char` or `wchar_t`.
|
||||
|
||||
\code{.cpp}
|
||||
cmd="value";
|
||||
cmd(value);
|
||||
\endcode
|
||||
|
||||
The property can only be used for assignments.
|
||||
|
||||
|
||||
*/
|
||||
constexpr static ::boost::process::v1::detail::cmd_ cmd;
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -11,26 +11,26 @@
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/posix.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/detail/posix/asio_fwd.hpp>
|
||||
#include <boost/process/v1/posix.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/asio_fwd.hpp>
|
||||
#else
|
||||
#include <boost/process/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/detail/windows/asio_fwd.hpp>
|
||||
#include <boost/process/v1/detail/windows/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/windows/asio_fwd.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
using ::boost::process::detail::posix::is_async_handler;
|
||||
using ::boost::process::detail::posix::does_require_io_context;
|
||||
using ::boost::process::v1::detail::posix::is_async_handler;
|
||||
using ::boost::process::v1::detail::posix::does_require_io_context;
|
||||
#else
|
||||
using ::boost::process::detail::windows::is_async_handler;
|
||||
using ::boost::process::detail::windows::does_require_io_context;
|
||||
using ::boost::process::v1::detail::windows::is_async_handler;
|
||||
using ::boost::process::v1::detail::windows::does_require_io_context;
|
||||
#endif
|
||||
|
||||
template<typename ...Args>
|
||||
@@ -112,6 +112,7 @@ boost::asio::io_context &get_io_context_var(First&, Args&...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_ASYNC_HANDLER_HPP_ */
|
||||
@@ -7,26 +7,26 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/detail/traits/wchar_t.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/traits/cmd_or_exe.hpp>
|
||||
#include <boost/process/v1/detail/traits/wchar_t.hpp>
|
||||
|
||||
#if defined( BOOST_WINDOWS_API )
|
||||
#include <boost/process/detail/windows/basic_cmd.hpp>
|
||||
#include <boost/process/detail/windows/cmd.hpp>
|
||||
#include <boost/process/v1/detail/windows/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/windows/cmd.hpp>
|
||||
#elif defined( BOOST_POSIX_API )
|
||||
#include <boost/process/detail/posix/basic_cmd.hpp>
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#include <boost/process/v1/detail/posix/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<typename Char>
|
||||
struct exe_setter_
|
||||
@@ -47,7 +47,7 @@ struct char_converter<char, exe_setter_<wchar_t>>
|
||||
{
|
||||
static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.exe_)};
|
||||
return {::boost::process::v1::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -56,7 +56,7 @@ struct char_converter<wchar_t, exe_setter_<char>>
|
||||
{
|
||||
static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
|
||||
{
|
||||
return {::boost::process::detail::convert(in.exe_)};
|
||||
return {::boost::process::v1::detail::convert(in.exe_)};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ struct char_converter<char, arg_setter_<wchar_t, true>>
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::wstring & ws)
|
||||
{
|
||||
return ::boost::process::detail::convert(ws);
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec};
|
||||
}
|
||||
@@ -120,7 +120,7 @@ struct char_converter<wchar_t, arg_setter_<char, true>>
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::string & ws)
|
||||
{
|
||||
return ::boost::process::detail::convert(ws);
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
|
||||
return {vec};
|
||||
@@ -136,7 +136,7 @@ struct char_converter<char, arg_setter_<wchar_t, false>>
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::wstring & ws)
|
||||
{
|
||||
return ::boost::process::detail::convert(ws);
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec}; }
|
||||
};
|
||||
@@ -150,7 +150,7 @@ struct char_converter<wchar_t, arg_setter_<char, false>>
|
||||
std::transform(in._args.begin(), in._args.end(), vec.begin(),
|
||||
[](const std::string & ws)
|
||||
{
|
||||
return ::boost::process::detail::convert(ws);
|
||||
return ::boost::process::v1::detail::convert(ws);
|
||||
});
|
||||
return {vec};
|
||||
}
|
||||
@@ -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::v1::filesystem::path & data)
|
||||
{
|
||||
not_cmd = true;
|
||||
if (exe.empty())
|
||||
@@ -285,7 +285,7 @@ struct initializer_builder<cmd_or_exe_tag<wchar_t>>
|
||||
typedef exe_builder<wchar_t> type;
|
||||
};
|
||||
|
||||
}}}
|
||||
}}}}
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#ifndef BOOST_PROCESS_CHILD_DECL_HPP
|
||||
#define BOOST_PROCESS_CHILD_DECL_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
@@ -25,42 +25,42 @@
|
||||
#include <atomic>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/detail/posix/terminate.hpp>
|
||||
#include <boost/process/detail/posix/wait_for_exit.hpp>
|
||||
#include <boost/process/detail/posix/is_running.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/posix/terminate.hpp>
|
||||
#include <boost/process/v1/detail/posix/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/posix/is_running.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/detail/windows/terminate.hpp>
|
||||
#include <boost/process/detail/windows/wait_for_exit.hpp>
|
||||
#include <boost/process/detail/windows/is_running.hpp>
|
||||
#include <boost/process/v1/detail/windows/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/windows/terminate.hpp>
|
||||
#include <boost/process/v1/detail/windows/wait_for_exit.hpp>
|
||||
#include <boost/process/v1/detail/windows/is_running.hpp>
|
||||
|
||||
#endif
|
||||
namespace boost {
|
||||
|
||||
namespace process {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
using ::boost::process::detail::api::pid_t;
|
||||
using ::boost::process::v1::detail::api::pid_t;
|
||||
|
||||
class child
|
||||
{
|
||||
::boost::process::detail::api::child_handle _child_handle;
|
||||
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active);
|
||||
::boost::process::v1::detail::api::child_handle _child_handle;
|
||||
std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::v1::detail::api::still_active);
|
||||
bool _attached = true;
|
||||
bool _terminated = false;
|
||||
|
||||
bool _exited()
|
||||
{
|
||||
return _terminated || !::boost::process::detail::api::is_running(_exit_status->load());
|
||||
return _terminated || !::boost::process::v1::detail::api::is_running(_exit_status->load());
|
||||
};
|
||||
public:
|
||||
typedef ::boost::process::detail::api::child_handle child_handle;
|
||||
typedef ::boost::process::v1::detail::api::child_handle child_handle;
|
||||
typedef child_handle::process_handle_t native_handle_t;
|
||||
explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
|
||||
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
|
||||
|
||||
explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
|
||||
explicit child(pid_t pid) : _child_handle(pid), _attached(false) {};
|
||||
child(const child&) = delete;
|
||||
child(child && lhs) noexcept
|
||||
: _child_handle(std::move(lhs._child_handle)),
|
||||
@@ -98,7 +98,7 @@ public:
|
||||
native_handle_t native_handle() const { return _child_handle.process_handle(); }
|
||||
|
||||
|
||||
int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());}
|
||||
int exit_code() const {return ::boost::process::v1::detail::api::eval_exit_status(_exit_status->load());}
|
||||
pid_t id() const {return _child_handle.id(); }
|
||||
|
||||
int native_exit_code() const {return _exit_status->load();}
|
||||
@@ -107,7 +107,7 @@ public:
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = running(ec);
|
||||
boost::process::detail::throw_error(ec, "running error");
|
||||
boost::process::v1::detail::throw_error(ec, "running error");
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -115,33 +115,38 @@ public:
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(ec);
|
||||
boost::process::detail::throw_error(ec, "terminate error");
|
||||
boost::process::v1::detail::throw_error(ec, "terminate error");
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
std::error_code ec;
|
||||
wait(ec);
|
||||
boost::process::detail::throw_error(ec, "wait error");
|
||||
boost::process::v1::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;
|
||||
bool b = wait_for(rel_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_for error");
|
||||
boost::process::v1::detail::throw_error(ec, "wait_for error");
|
||||
return b;
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = wait_until(timeout_time, ec);
|
||||
boost::process::detail::throw_error(ec, "wait_until error");
|
||||
boost::process::v1::detail::throw_error(ec, "wait_until error");
|
||||
return b;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool running(std::error_code & ec) noexcept
|
||||
{
|
||||
@@ -149,7 +154,7 @@ public:
|
||||
if (valid() && !_exited() && !ec)
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
|
||||
auto res = boost::process::v1::detail::api::is_running(_child_handle, exit_code, ec);
|
||||
if (!ec && !res && !_exited())
|
||||
_exit_status->store(exit_code);
|
||||
|
||||
@@ -161,7 +166,7 @@ public:
|
||||
void terminate(std::error_code & ec) noexcept
|
||||
{
|
||||
if (valid() && running(ec) && !ec)
|
||||
boost::process::detail::api::terminate(_child_handle, ec);
|
||||
boost::process::v1::detail::api::terminate(_child_handle, ec);
|
||||
|
||||
if (!ec)
|
||||
_terminated = true;
|
||||
@@ -172,32 +177,35 @@ public:
|
||||
if (!_exited() && valid())
|
||||
{
|
||||
int exit_code = 0;
|
||||
boost::process::detail::api::wait(_child_handle, exit_code, ec);
|
||||
boost::process::v1::detail::api::wait(_child_handle, exit_code, ec);
|
||||
if (!ec)
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
|
||||
}
|
||||
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
if (!_exited())
|
||||
{
|
||||
int exit_code = 0;
|
||||
auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
|
||||
auto b = boost::process::v1::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec);
|
||||
if (!b || ec)
|
||||
return false;
|
||||
_exit_status->store(exit_code);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
@@ -217,6 +225,7 @@ public:
|
||||
|
||||
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,19 @@
|
||||
#include <system_error>
|
||||
#include <boost/system/api_config.hpp>
|
||||
|
||||
#include <boost/process/exception.hpp>
|
||||
#if !defined(BOOST_PROCESS_VERSION)
|
||||
#define BOOST_PROCESS_VERSION 1
|
||||
#endif
|
||||
|
||||
#if BOOST_PROCESS_VERSION == 1
|
||||
#define BOOST_PROCESS_V1_INLINE inline
|
||||
#else
|
||||
#define BOOST_PROCESS_V1_INLINE
|
||||
#endif
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/process/v1/exception.hpp>
|
||||
#include <boost/assert/source_location.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <errno.h>
|
||||
@@ -36,7 +48,9 @@ extern char **environ;
|
||||
#error "System API not supported by boost.process"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace process { namespace detail
|
||||
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail
|
||||
{
|
||||
|
||||
#if !defined(BOOST_PROCESS_PIPE_SIZE)
|
||||
@@ -71,31 +85,33 @@ inline std::error_code get_last_error() noexcept
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void throw_last_error(const std::string & msg)
|
||||
inline void throw_last_error(const std::string & msg, boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
throw process_error(get_last_error(), msg);
|
||||
boost::throw_exception(process_error(get_last_error(), msg), loc);
|
||||
}
|
||||
|
||||
inline void throw_last_error(const char * msg)
|
||||
inline void throw_last_error(const char * msg, boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
throw process_error(get_last_error(), msg);
|
||||
boost::throw_exception(process_error(get_last_error(), msg), loc);
|
||||
}
|
||||
|
||||
inline void throw_last_error()
|
||||
inline void throw_last_error(boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
throw process_error(get_last_error());
|
||||
boost::throw_exception(process_error(get_last_error()), loc);
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec)
|
||||
inline void throw_error(const std::error_code& ec,
|
||||
boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
if (ec)
|
||||
throw process_error(ec);
|
||||
boost::throw_exception(process_error(ec), loc);
|
||||
}
|
||||
|
||||
inline void throw_error(const std::error_code& ec, const char* msg)
|
||||
inline void throw_error(const std::error_code& ec, const char* msg,
|
||||
boost::source_location const & loc = boost::source_location())
|
||||
{
|
||||
if (ec)
|
||||
throw process_error(ec, msg);
|
||||
boost::throw_exception(process_error(ec, msg), loc);
|
||||
}
|
||||
|
||||
template<typename Char> constexpr Char null_char();
|
||||
@@ -114,6 +130,10 @@ 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
|
||||
@@ -17,17 +17,17 @@
|
||||
#ifndef BOOST_PROCESS_EXECUTE_HPP
|
||||
#define BOOST_PROCESS_EXECUTE_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/traits.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/traits.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/executor.hpp>
|
||||
#include <boost/process/v1/detail/posix/executor.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/executor.hpp>
|
||||
#include <boost/process/v1/detail/windows/executor.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/process/detail/basic_cmd.hpp>
|
||||
#include <boost/process/detail/handler.hpp>
|
||||
#include <boost/process/v1/detail/basic_cmd.hpp>
|
||||
#include <boost/process/v1/detail/handler.hpp>
|
||||
|
||||
#include <boost/fusion/view.hpp>
|
||||
#include <boost/fusion/container.hpp>
|
||||
@@ -40,7 +40,7 @@
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
class child;
|
||||
|
||||
@@ -228,7 +228,7 @@ inline child basic_execute_impl(Args && ... args)
|
||||
boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
|
||||
|
||||
auto inits = boost::fusion::filter_if<
|
||||
boost::process::detail::is_initializer<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
@@ -237,7 +237,7 @@ inline child basic_execute_impl(Args && ... args)
|
||||
|
||||
auto others = boost::fusion::filter_if<
|
||||
boost::mpl::not_<
|
||||
boost::process::detail::is_initializer<
|
||||
boost::process::v1::detail::is_initializer<
|
||||
typename std::remove_reference<
|
||||
boost::mpl::_
|
||||
>::type
|
||||
@@ -250,20 +250,20 @@ inline child basic_execute_impl(Args && ... args)
|
||||
//typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type inits_t;
|
||||
typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
|
||||
// typedef decltype(others) others_t;
|
||||
typedef typename ::boost::process::detail::make_builders_from_view<
|
||||
typedef typename ::boost::process::v1::detail::make_builders_from_view<
|
||||
typename boost::fusion::result_of::begin<others_t>::type,
|
||||
typename boost::fusion::result_of::end <others_t>::type>::type builder_t;
|
||||
|
||||
builder_t builders;
|
||||
::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
|
||||
::boost::process::v1::detail::builder_ref<builder_t> builder_ref(builders);
|
||||
|
||||
boost::fusion::for_each(others, builder_ref);
|
||||
auto other_inits = ::boost::process::detail::get_initializers(builders);
|
||||
auto other_inits = ::boost::process::v1::detail::get_initializers(builders);
|
||||
|
||||
|
||||
boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
|
||||
|
||||
auto exec = boost::process::detail::api::make_executor<Char>(complete_inits);
|
||||
auto exec = boost::process::v1::detail::api::make_executor<Char>(complete_inits);
|
||||
return exec();
|
||||
}
|
||||
|
||||
@@ -273,12 +273,11 @@ inline child execute_impl(Args&& ... args)
|
||||
typedef required_char_type_t<Args...> req_char_type;
|
||||
|
||||
return basic_execute_impl<req_char_type>(
|
||||
boost::process::detail::char_converter_t<req_char_type, Args>::conv(
|
||||
boost::process::v1::detail::char_converter_t<req_char_type, Args>::conv(
|
||||
std::forward<Args>(args))...
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,16 +7,16 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/handler.hpp>
|
||||
#include <boost/process/v1/detail/windows/handler.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
//extended handler base.
|
||||
typedef api::handler_base_ext handler;
|
||||
@@ -68,8 +68,6 @@ private:
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_HANDLER_HPP_ */
|
||||
@@ -11,9 +11,10 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
#define BOOST_PROCESS_DETAIL_HANDLER_BASE_HPP
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
template<template <class> class Template>
|
||||
struct make_handler_t
|
||||
@@ -44,6 +45,6 @@ struct handler_base
|
||||
};
|
||||
|
||||
|
||||
}}}
|
||||
}}}}
|
||||
|
||||
#endif
|
||||
@@ -6,18 +6,18 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_ON_EXIT_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_POSIX_API)
|
||||
#include <boost/process/detail/posix/on_exit.hpp>
|
||||
#include <boost/process/v1/detail/posix/on_exit.hpp>
|
||||
#elif defined(BOOST_WINDOWS_API)
|
||||
#include <boost/process/detail/windows/on_exit.hpp>
|
||||
#include <boost/process/v1/detail/windows/on_exit.hpp>
|
||||
#endif
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { namespace detail {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail {
|
||||
|
||||
inline std::function<void(int, const std::error_code &)> on_exit_from_future(std::future<int> &f)
|
||||
{
|
||||
@@ -46,8 +46,9 @@ struct on_exit_
|
||||
|
||||
}
|
||||
|
||||
constexpr static ::boost::process::detail::on_exit_ on_exit{};
|
||||
constexpr static ::boost::process::v1::detail::on_exit_ on_exit{};
|
||||
|
||||
|
||||
}}
|
||||
}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_ */
|
||||
@@ -38,7 +38,7 @@ typedef basic_stream_descriptor<any_io_executor> stream_descriptor;
|
||||
} //posix
|
||||
} //asio
|
||||
|
||||
namespace process { namespace detail { namespace posix {
|
||||
namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe;
|
||||
|
||||
@@ -54,8 +54,9 @@ struct async_out_future;
|
||||
} // posix
|
||||
} // detail
|
||||
|
||||
using ::boost::process::detail::posix::async_pipe;
|
||||
using ::boost::process::v1::detail::posix::async_pipe;
|
||||
|
||||
} // v1
|
||||
} // process
|
||||
} // boost
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#ifndef BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_POSIX_ASYNC_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct require_io_context {};
|
||||
|
||||
@@ -35,6 +35,6 @@ template<typename T>
|
||||
struct does_require_io_context<const T&> : std::is_base_of<require_io_context, T> {};
|
||||
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_ASYNC_HANDLER_HPP_ */
|
||||
@@ -10,22 +10,22 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_IN_HPP
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<typename Buffer>
|
||||
struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
struct async_in_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
@@ -37,7 +37,7 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
async_in_buffer(Buffer & buf) : buf(buf)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
if (!pipe)
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
std::array<int, 3> get_used_handles()
|
||||
@@ -97,7 +97,7 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
void on_exec_setup(Executor &exec)
|
||||
{
|
||||
if (::dup2(pipe->native_source(), STDIN_FILENO) == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (pipe->native_source() != STDIN_FILENO)
|
||||
::close(pipe->native_source());
|
||||
@@ -106,6 +106,6 @@ struct async_in_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,18 +11,18 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_OUT_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/process/async_pipe.hpp>
|
||||
#include <boost/process/v1/async_pipe.hpp>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
#include <future>
|
||||
#include <array>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::integral_constant<int, -1>)
|
||||
@@ -46,13 +46,13 @@ inline int apply_out_handles(int handle, std::integral_constant<int, 1>, std::in
|
||||
}
|
||||
|
||||
template<int p1, int p2, typename Buffer>
|
||||
struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context,
|
||||
::boost::process::detail::uses_handles
|
||||
struct async_out_buffer : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context,
|
||||
::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
Buffer & buf;
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
std::array<int, 4> get_used_handles()
|
||||
{
|
||||
@@ -71,7 +71,7 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
inline void on_success(Executor &exec)
|
||||
inline void on_success(Executor &)
|
||||
{
|
||||
auto pipe = this->pipe;
|
||||
boost::asio::async_read(*pipe, buf,
|
||||
@@ -90,7 +90,7 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
int res = apply_out_handles(pipe->native_sink(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
@@ -112,14 +112,14 @@ struct async_out_buffer : ::boost::process::detail::posix::handler_base_ext,
|
||||
|
||||
|
||||
template<int p1, int p2, typename Type>
|
||||
struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
::boost::process::detail::posix::require_io_context
|
||||
struct async_out_future : ::boost::process::v1::detail::posix::handler_base_ext,
|
||||
::boost::process::v1::detail::posix::require_io_context
|
||||
{
|
||||
std::shared_ptr<std::promise<Type>> promise = std::make_shared<std::promise<Type>>();
|
||||
|
||||
std::shared_ptr<boost::asio::streambuf> buffer = std::make_shared<boost::asio::streambuf>();
|
||||
|
||||
std::shared_ptr<boost::process::async_pipe> pipe;
|
||||
std::shared_ptr<boost::process::v1::async_pipe> pipe;
|
||||
|
||||
async_out_future(std::future<Type> & fut)
|
||||
{
|
||||
@@ -167,7 +167,7 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
template<typename Executor>
|
||||
void on_setup(Executor & exec)
|
||||
{
|
||||
pipe = std::make_shared<boost::process::async_pipe>(get_io_context(exec.seq));
|
||||
pipe = std::make_shared<boost::process::v1::async_pipe>(get_io_context(exec.seq));
|
||||
}
|
||||
|
||||
template <typename Executor>
|
||||
@@ -177,7 +177,7 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
int res = apply_out_handles(pipe->native_sink(),
|
||||
std::integral_constant<int, p1>(), std::integral_constant<int, p2>());
|
||||
if (res == -1)
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
::close(pipe->native_sink());
|
||||
::close(pipe->native_source());
|
||||
@@ -185,6 +185,6 @@ struct async_out_future : ::boost::process::detail::posix::handler_base_ext,
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,14 +7,14 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ASYNC_PIPE_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/asio/posix/stream_descriptor.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <system_error>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
class async_pipe
|
||||
{
|
||||
@@ -25,6 +25,11 @@ public:
|
||||
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) {}
|
||||
|
||||
inline async_pipe(boost::asio::io_context & ios_source,
|
||||
@@ -32,7 +37,7 @@ public:
|
||||
{
|
||||
int fds[2];
|
||||
if (::pipe(fds) == -1)
|
||||
boost::process::detail::throw_last_error("pipe(2) failed");
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_source.assign(fds[0]);
|
||||
_sink .assign(fds[1]);
|
||||
@@ -45,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>>
|
||||
@@ -200,18 +205,18 @@ async_pipe::async_pipe(boost::asio::io_context & ios_source,
|
||||
auto fifo = mkfifo(name.c_str(), 0666 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::detail::throw_last_error("mkfifo() failed");
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
_source.assign(read_fd);
|
||||
_sink .assign(write_fd);
|
||||
@@ -231,7 +236,7 @@ async_pipe::async_pipe(const async_pipe & p) :
|
||||
{
|
||||
_source.assign(::dup(source_in));
|
||||
if (_source.native_handle()== -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -240,7 +245,7 @@ async_pipe::async_pipe(const async_pipe & p) :
|
||||
{
|
||||
_sink.assign(::dup(sink_in));
|
||||
if (_sink.native_handle() == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +263,7 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -267,7 +272,7 @@ async_pipe& async_pipe::operator=(const async_pipe & p)
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
_source.assign(source);
|
||||
_sink. assign(sink);
|
||||
@@ -299,7 +304,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
source = ::dup(source_in);
|
||||
if (source == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
if (sink_in == -1)
|
||||
@@ -308,7 +313,7 @@ async_pipe::operator basic_pipe<CharT, Traits>() const
|
||||
{
|
||||
sink = ::dup(sink_in);
|
||||
if (sink == -1)
|
||||
::boost::process::detail::throw_last_error("dup()");
|
||||
::boost::process::v1::detail::throw_last_error("dup()");
|
||||
}
|
||||
|
||||
return basic_pipe<CharT, Traits>{source, sink};
|
||||
@@ -355,6 +360,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const async_pipe &
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif /* INCLUDE_BOOST_PIPE_DETAIL_WINDOWS_ASYNC_PIPE_HPP_ */
|
||||
@@ -7,10 +7,11 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_BASIC_CMD_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/cmd.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/cmd.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/process/shell.hpp>
|
||||
#include <boost/process/v1/shell.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <string>
|
||||
@@ -20,12 +21,13 @@ namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
|
||||
|
||||
inline std::string build_cmd_shell(const std::string & exe, std::vector<std::string> && data)
|
||||
{
|
||||
std::string st = exe;
|
||||
@@ -39,10 +41,10 @@ inline std::string build_cmd_shell(const std::string & exe, std::vector<std::str
|
||||
//the first one is put directly onto the output,
|
||||
//because then I don't have to copy the whole string
|
||||
arg.insert(arg.begin(), '"' );
|
||||
arg += '"'; //thats the post one.
|
||||
arg += '"'; //that is the post one.
|
||||
}
|
||||
|
||||
if (!st.empty())//first one does not need a preceeding space
|
||||
if (!st.empty())//first one does not need a preceding space
|
||||
st += ' ';
|
||||
|
||||
st += arg;
|
||||
@@ -101,7 +103,7 @@ template<typename Char>
|
||||
struct exe_cmd_init;
|
||||
|
||||
template<>
|
||||
struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
|
||||
struct exe_cmd_init<char> : boost::process::v1::detail::api::handler_base_ext
|
||||
{
|
||||
exe_cmd_init(const exe_cmd_init & ) = delete;
|
||||
exe_cmd_init(exe_cmd_init && ) = default;
|
||||
@@ -112,7 +114,10 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
|
||||
{
|
||||
if (exe.empty()) //cmd style
|
||||
{
|
||||
exec.exe = args.front().c_str();
|
||||
if (args.empty())
|
||||
exec.exe = "";
|
||||
else
|
||||
exec.exe = args.front().c_str();
|
||||
exec.cmd_style = true;
|
||||
}
|
||||
else
|
||||
@@ -139,7 +144,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(
|
||||
@@ -155,13 +160,15 @@ private:
|
||||
|
||||
std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
{
|
||||
// any string must be writable.
|
||||
static char empty_string[1] = "";
|
||||
std::vector<char*> vec;
|
||||
if (!exe.empty())
|
||||
vec.push_back(&exe.front());
|
||||
vec.push_back(exe.empty() ? empty_string : &exe.front());
|
||||
|
||||
if (!args.empty()) {
|
||||
for (auto & v : args)
|
||||
vec.push_back(&v.front());
|
||||
vec.push_back(v.empty() ? empty_string : &v.front());
|
||||
}
|
||||
|
||||
vec.push_back(nullptr);
|
||||
@@ -170,6 +177,6 @@ std::vector<char*> exe_cmd_init<char>::make_cmd()
|
||||
}
|
||||
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,15 +11,15 @@
|
||||
#define BOOST_PROCESS_POSIX_PIPE_HPP
|
||||
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/process/detail/posix/compare_handles.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/process/v1/detail/posix/compare_handles.hpp>
|
||||
#include <system_error>
|
||||
#include <array>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
template<class CharT, class Traits = std::char_traits<CharT>>
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
{
|
||||
int fds[2];
|
||||
if (::pipe(fds) == -1)
|
||||
boost::process::detail::throw_last_error("pipe(2) failed");
|
||||
boost::process::v1::detail::throw_last_error("pipe(2) failed");
|
||||
|
||||
_source = fds[0];
|
||||
_sink = fds[1];
|
||||
@@ -77,32 +77,29 @@ public:
|
||||
void assign_source(native_handle_type h) { _source = h;}
|
||||
void assign_sink (native_handle_type h) { _sink = h;}
|
||||
|
||||
|
||||
|
||||
|
||||
int_type write(const char_type * data, int_type count)
|
||||
{
|
||||
int_type write_len;
|
||||
ssize_t write_len;
|
||||
while ((write_len = ::write(_sink, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return write_len;
|
||||
return static_cast<int_type>(write_len);
|
||||
}
|
||||
int_type read(char_type * data, int_type count)
|
||||
{
|
||||
int_type read_len;
|
||||
ssize_t read_len;
|
||||
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
|
||||
{
|
||||
//Try again if interrupted
|
||||
auto err = errno;
|
||||
if (err != EINTR)
|
||||
::boost::process::detail::throw_last_error();
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
return read_len;
|
||||
return static_cast<int_type>(read_len);
|
||||
}
|
||||
|
||||
bool is_open() const
|
||||
@@ -129,13 +126,13 @@ basic_pipe<CharT, Traits>::basic_pipe(const basic_pipe & rhs)
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -147,13 +144,13 @@ basic_pipe<CharT, Traits> &basic_pipe<CharT, Traits>::operator=(const basic_pipe
|
||||
{
|
||||
_source = ::dup(rhs._source);
|
||||
if (_source == -1)
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
}
|
||||
if (rhs._sink != -1)
|
||||
{
|
||||
_sink = ::dup(rhs._sink);
|
||||
if (_sink == -1)
|
||||
::boost::process::detail::throw_last_error("dup() failed");
|
||||
::boost::process::v1::detail::throw_last_error("dup() failed");
|
||||
|
||||
}
|
||||
return *this;
|
||||
@@ -166,18 +163,18 @@ basic_pipe<CharT, Traits>::basic_pipe(const std::string & name)
|
||||
auto fifo = mkfifo(name.c_str(), 0666 );
|
||||
|
||||
if (fifo != 0)
|
||||
boost::process::detail::throw_last_error("mkfifo() failed");
|
||||
boost::process::v1::detail::throw_last_error("mkfifo() failed");
|
||||
|
||||
|
||||
int read_fd = open(name.c_str(), O_RDWR);
|
||||
|
||||
if (read_fd == -1)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
int write_fd = dup(read_fd);
|
||||
|
||||
if (write_fd == -1)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
|
||||
_sink = write_fd;
|
||||
_source = read_fd;
|
||||
@@ -198,6 +195,6 @@ inline bool operator!=(const basic_pipe<Char, Traits> & lhs, const basic_pipe<Ch
|
||||
!compare_handles(lhs.native_sink(), rhs.native_sink());
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <utility>
|
||||
#include <system_error>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
typedef ::pid_t pid_t;
|
||||
|
||||
@@ -55,6 +55,6 @@ struct child_handle
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,24 +11,24 @@
|
||||
#define BOOST_PROCESS_WINDOWS_INITIALIZERS_CLOSE_IN_HPP
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct close_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
template <class Executor>
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return STDIN_FILENO;}
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -10,11 +10,11 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CLOSE_OUT_HPP
|
||||
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct close_out : handler_base_ext
|
||||
@@ -30,7 +30,7 @@ template<typename Executor>
|
||||
void close_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ template<typename Executor>
|
||||
void close_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -47,12 +47,12 @@ template<typename Executor>
|
||||
void close_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::close(STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
|
||||
if (::close(STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,8 +7,8 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_CMD_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
@@ -99,6 +101,6 @@ std::vector<Char*> cmd_setter_<Char>::make_cmd(std::vector<std::basic_string<Cha
|
||||
return vec;
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -7,12 +7,12 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_COMPARE_HANDLES_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
inline bool compare_handles(int lhs, int rhs)
|
||||
@@ -25,8 +25,8 @@ inline bool compare_handles(int lhs, int rhs)
|
||||
return true;
|
||||
|
||||
struct stat stat1, stat2;
|
||||
if(fstat(lhs, &stat1) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(rhs, &stat2) < 0) ::boost::process::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(lhs, &stat1) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
if(fstat(rhs, &stat2) < 0) ::boost::process::v1::detail::throw_last_error("fstat() failed");
|
||||
|
||||
return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
|
||||
}
|
||||
@@ -35,7 +35,7 @@ inline bool compare_handles(int lhs, int rhs)
|
||||
|
||||
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_ENV_INIT_HPP_
|
||||
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/environment.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/environment.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
struct env_init;
|
||||
@@ -20,10 +20,10 @@ struct env_init;
|
||||
template<>
|
||||
struct env_init<char> : handler_base_ext
|
||||
{
|
||||
boost::process::environment env;
|
||||
boost::process::v1::environment env;
|
||||
|
||||
env_init(boost::process::environment && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::environment & env) : env(env) {};
|
||||
env_init(boost::process::v1::environment && env) : env(std::move(env)) {};
|
||||
env_init(const boost::process::v1::environment & env) : env(env) {};
|
||||
|
||||
|
||||
template <class Executor>
|
||||
@@ -34,7 +34,7 @@ struct env_init<char> : handler_base_ext
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/locale.hpp>
|
||||
#include <boost/process/v1/locale.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Char>
|
||||
class native_environment_impl
|
||||
@@ -27,7 +27,7 @@ class native_environment_impl
|
||||
while (*p != nullptr)
|
||||
{
|
||||
std::string str = *p;
|
||||
val.push_back(::boost::process::detail::convert(str));
|
||||
val.push_back(::boost::process::v1::detail::convert(str));
|
||||
p++;
|
||||
}
|
||||
return val;
|
||||
@@ -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)); }
|
||||
@@ -67,24 +68,24 @@ public:
|
||||
|
||||
string_type get(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::detail::convert(id);
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id);
|
||||
std::string g = ::getenv(id_c.c_str());
|
||||
return ::boost::process::detail::convert(g.c_str());
|
||||
return ::boost::process::v1::detail::convert(g.c_str());
|
||||
}
|
||||
void set(const string_type & id, const string_type & value)
|
||||
{
|
||||
std::string id_c = ::boost::process::detail::convert(id.c_str());
|
||||
std::string value_c = ::boost::process::detail::convert(value.c_str());
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
std::string value_c = ::boost::process::v1::detail::convert(value.c_str());
|
||||
auto res = ::setenv(id_c.c_str(), value_c.c_str(), true);
|
||||
if (res != 0)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
void reset(const string_type & id)
|
||||
{
|
||||
std::string id_c = ::boost::process::detail::convert(id.c_str());
|
||||
std::string id_c = ::boost::process::v1::detail::convert(id.c_str());
|
||||
auto res = ::unsetenv(id_c.c_str());
|
||||
if (res != 0)
|
||||
::boost::process::detail::throw_last_error();
|
||||
::boost::process::v1::detail::throw_last_error();
|
||||
}
|
||||
|
||||
native_environment_impl() = default;
|
||||
@@ -113,14 +114,14 @@ public:
|
||||
{
|
||||
auto res = ::setenv(id, value, 1);
|
||||
if (res != 0)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
void reset(const pointer_type id)
|
||||
{
|
||||
auto res = ::unsetenv(id);
|
||||
if (res != 0)
|
||||
boost::process::detail::throw_last_error();
|
||||
boost::process::v1::detail::throw_last_error();
|
||||
reload();
|
||||
}
|
||||
|
||||
@@ -185,13 +186,13 @@ public:
|
||||
template<typename CharR>
|
||||
explicit inline basic_environment_impl(
|
||||
const basic_environment_impl<CharR>& rhs,
|
||||
const ::boost::process::codecvt_type & cv = ::boost::process::codecvt())
|
||||
const ::boost::process::v1::codecvt_type & cv = ::boost::process::v1::codecvt())
|
||||
: _data(rhs._data.size())
|
||||
{
|
||||
std::transform(rhs._data.begin(), rhs._data.end(), _data.begin(),
|
||||
[&](const std::basic_string<CharR> & st)
|
||||
{
|
||||
return ::boost::process::detail::convert(st, cv);
|
||||
return ::boost::process::v1::detail::convert(st, cv);
|
||||
}
|
||||
|
||||
);
|
||||
@@ -201,7 +202,7 @@ public:
|
||||
template<typename CharR>
|
||||
basic_environment_impl & operator=(const basic_environment_impl<CharR>& rhs)
|
||||
{
|
||||
_data = ::boost::process::detail::convert(rhs._data);
|
||||
_data = ::boost::process::v1::detail::convert(rhs._data);
|
||||
_env_arr = _load_var(&*_data.begin());
|
||||
_env_impl = &*_env_arr.begin();
|
||||
return *this;
|
||||
@@ -229,7 +230,7 @@ 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
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
@@ -249,7 +250,7 @@ inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_t
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::set(const string_type &id, const string_type &value)
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
@@ -260,7 +261,7 @@ inline void basic_environment_impl<Char>::set(const string_type &id, const strin
|
||||
|
||||
if (itr != _data.end())
|
||||
*itr = id + equal_sign<Char>() + value;
|
||||
else
|
||||
else
|
||||
_data.push_back(id + equal_sign<Char>() + value);
|
||||
|
||||
reload();
|
||||
@@ -269,7 +270,7 @@ inline void basic_environment_impl<Char>::set(const string_type &id, const strin
|
||||
template<typename Char>
|
||||
inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
{
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
auto itr = std::find_if(_data.begin(), _data.end(),
|
||||
[&](const string_type & st) -> bool
|
||||
{
|
||||
if (st.size() <= id.size())
|
||||
@@ -279,9 +280,9 @@ inline void basic_environment_impl<Char>::reset(const string_type &id)
|
||||
);
|
||||
if (itr != _data.end())
|
||||
{
|
||||
_data.erase(itr);//and remove it
|
||||
_data.erase(itr);//and remove it
|
||||
}
|
||||
|
||||
|
||||
reload();
|
||||
|
||||
|
||||
@@ -319,7 +320,7 @@ inline int native_handle() {return getpid(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXE_HPP_
|
||||
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
BOOST_PROCESS_V1_INLINE namespace v1
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace posix
|
||||
@@ -30,7 +33,7 @@ inline void apply_exe(const StringType & exe, Executor & e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* INCLUDE_BOOST_PROCESS_WINDOWS_ARGS_HPP_ */
|
||||
@@ -10,11 +10,11 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_EXECUTOR_HPP
|
||||
|
||||
#include <boost/process/detail/child_decl.hpp>
|
||||
#include <boost/process/error.hpp>
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/detail/posix/use_vfork.hpp>
|
||||
#include <boost/process/v1/detail/child_decl.hpp>
|
||||
#include <boost/process/v1/error.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/basic_pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/use_vfork.hpp>
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
#include <cstdlib>
|
||||
#include <sys/types.h>
|
||||
@@ -26,7 +26,9 @@
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_setup_t
|
||||
@@ -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_)
|
||||
@@ -202,9 +204,9 @@ class executor
|
||||
throw process_error(_ec, _msg);
|
||||
}
|
||||
|
||||
typedef typename ::boost::process::detail::has_error_handler<Sequence>::type has_error_handler;
|
||||
typedef typename ::boost::process::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
typedef typename ::boost::process::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
|
||||
typedef typename ::boost::process::v1::detail::has_error_handler<Sequence>::type has_error_handler;
|
||||
typedef typename ::boost::process::v1::detail::has_ignore_error <Sequence>::type has_ignore_error;
|
||||
typedef typename ::boost::process::v1::detail::posix::shall_use_vfork<Sequence>::type shall_use_vfork;
|
||||
|
||||
inline child invoke(boost::mpl::true_ , boost::mpl::true_ );
|
||||
inline child invoke(boost::mpl::false_, boost::mpl::true_ );
|
||||
@@ -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;
|
||||
const auto * e = ::environ;
|
||||
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
|
||||
e++;
|
||||
|
||||
if ((e != nullptr) && (*e != nullptr))
|
||||
{
|
||||
std::vector<std::string> path;
|
||||
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>
|
||||
@@ -339,7 +349,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
@@ -347,7 +357,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::false_) //ignore
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -379,21 +389,25 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
|
||||
if (::pipe(p.p) == -1)
|
||||
{
|
||||
set_error(::boost::process::detail::get_last_error(), "pipe(2) failed");
|
||||
set_error(::boost::process::v1::detail::get_last_error(), "pipe(2) failed");
|
||||
return child();
|
||||
}
|
||||
if (::fcntl(p.p[1], F_SETFD, FD_CLOEXEC) == -1)
|
||||
{
|
||||
auto err = ::boost::process::detail::get_last_error();
|
||||
auto err = ::boost::process::v1::detail::get_last_error();
|
||||
set_error(err, "fcntl(2) failed");//this might throw, so we need to be sure our pipe is safe.
|
||||
return child();
|
||||
}
|
||||
|
||||
_pipe_sink = p.p[1];
|
||||
|
||||
_ec.clear();
|
||||
boost::fusion::for_each(seq, call_on_setup(*this));
|
||||
|
||||
if (_ec)
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
|
||||
@@ -403,20 +417,20 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
this->pid = ::fork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
_pipe_sink = -1;
|
||||
return child();
|
||||
}
|
||||
else if (pid == 0)
|
||||
{
|
||||
_pipe_sink = p.p[1];
|
||||
::close(p.p[0]);
|
||||
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
@@ -429,11 +443,14 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
|
||||
|
||||
::close(p.p[1]);
|
||||
p.p[1] = -1;
|
||||
_pipe_sink = -1;
|
||||
_read_error(p.p[0]);
|
||||
|
||||
}
|
||||
if (_ec)
|
||||
{
|
||||
//if an error occurred we need to reap the child process
|
||||
::waitpid(this->pid, nullptr, WNOHANG);
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
return child();
|
||||
}
|
||||
@@ -463,7 +480,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, ec));
|
||||
return child();
|
||||
}
|
||||
@@ -471,7 +488,7 @@ child executor<Sequence>::invoke(boost::mpl::true_, boost::mpl::true_) //ignore
|
||||
{
|
||||
boost::fusion::for_each(seq, call_on_exec_setup(*this));
|
||||
::execve(exe, cmd_line, env);
|
||||
auto ec = boost::process::detail::get_last_error();
|
||||
auto ec = boost::process::v1::detail::get_last_error();
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, ec));
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -499,7 +516,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
this->pid = ::vfork();
|
||||
if (pid == -1)
|
||||
{
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "fork() failed";
|
||||
boost::fusion::for_each(seq, call_on_fork_error(*this, _ec));
|
||||
boost::fusion::for_each(seq, call_on_error(*this, _ec));
|
||||
@@ -512,7 +529,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
|
||||
|
||||
::execve(exe, cmd_line, env);
|
||||
|
||||
_ec = boost::process::detail::get_last_error();
|
||||
_ec = boost::process::v1::detail::get_last_error();
|
||||
_msg = "execve failed";
|
||||
boost::fusion::for_each(seq, call_on_exec_error(*this, _ec));
|
||||
|
||||
@@ -527,6 +544,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();
|
||||
}
|
||||
@@ -550,6 +568,6 @@ inline executor<Tup> make_executor(Tup & tup)
|
||||
return executor<Tup>(tup);
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -10,15 +10,15 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FD_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FD_HPP
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
close_fd_(int fd) : fd_(fd) {}
|
||||
|
||||
@@ -26,7 +26,7 @@ struct close_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
void on_exec_setup(PosixExecutor& e) const
|
||||
{
|
||||
if (::close(fd_) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
}
|
||||
|
||||
int get_used_handles() {return fd_;}
|
||||
@@ -37,7 +37,7 @@ private:
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
struct close_fds_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct close_fds_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
close_fds_(const Range &fds) : fds_(fds) {}
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
for (auto & fd_ : fds_)
|
||||
if (::close(fd_) == -1)
|
||||
{
|
||||
e.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,7 @@ private:
|
||||
|
||||
|
||||
template <class FileDescriptor>
|
||||
struct bind_fd_ : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct bind_fd_ : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
public:
|
||||
bind_fd_(int id, const FileDescriptor &fd) : id_(id), fd_(fd) {}
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
void on_exec_setup(PosixExecutor& e) const
|
||||
{
|
||||
if (::dup2(fd_, id_) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
std::array<int, 2> get_used_handles() {return {id_, fd_};}
|
||||
@@ -97,6 +97,6 @@ struct fd_
|
||||
};
|
||||
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -8,9 +8,10 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
#include <boost/core/exchange.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct file_descriptor
|
||||
{
|
||||
@@ -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::v1::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()
|
||||
{
|
||||
@@ -71,6 +84,6 @@ private:
|
||||
int _handle = -1;
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_FILE_DESCRIPTOR_HPP_ */
|
||||
@@ -10,16 +10,16 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_FILE_IN_HPP
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct file_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
@@ -37,10 +37,10 @@ struct file_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
void on_exec_setup(WindowsExecutor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -11,15 +11,15 @@
|
||||
#ifndef BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
#define BOOST_PROCESS_POSIX_FILE_OUT_HPP
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/detail/used_handles.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/detail/used_handles.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<int p1, int p2>
|
||||
struct file_out : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct file_out : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor file;
|
||||
int handle = file.handle();
|
||||
@@ -45,7 +45,7 @@ template<typename Executor>
|
||||
void file_out<1,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -53,7 +53,7 @@ template<typename Executor>
|
||||
void file_out<2,-1>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -61,13 +61,13 @@ template<typename Executor>
|
||||
void file_out<1,2>::on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(handle, STDOUT_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
if (::dup2(handle, STDERR_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
e.set_error(::boost::process::v1::detail::get_last_error(), "dup2() failed");
|
||||
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user