mirror of
https://github.com/boostorg/process.git
synced 2026-01-19 16:32:15 +00:00
Compare commits
155 Commits
noexcept
...
boost-1.87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa83c2f9ff | ||
|
|
9925e82a5f | ||
|
|
7f03295c93 | ||
|
|
64c4cdac83 | ||
|
|
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 |
@@ -19,7 +19,7 @@ def main(ctx):
|
||||
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 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:
|
||||
|
||||
@@ -26,9 +26,7 @@ set B2_TARGETS=libs/!SELF!/test
|
||||
cd !BOOST_ROOT!
|
||||
call bootstrap.bat
|
||||
b2 headers
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test -j3
|
||||
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/example -j3
|
||||
|
||||
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
|
||||
|
||||
211
.github/workflows/ci.yml
vendored
211
.github/workflows/ci.yml
vendored
@@ -17,10 +17,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- toolset: gcc-4.8
|
||||
cxxstd: "11"
|
||||
os: ubuntu-18.04
|
||||
install: g++-4.8
|
||||
- toolset: gcc-5
|
||||
cxxstd: "11,14,1z"
|
||||
os: ubuntu-18.04
|
||||
@@ -32,21 +28,10 @@ jobs:
|
||||
- toolset: gcc-7
|
||||
cxxstd: "11,14,17"
|
||||
os: ubuntu-18.04
|
||||
- toolset: gcc-8
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-18.04
|
||||
install: g++-8
|
||||
- toolset: gcc-9
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
- toolset: gcc-10
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-10
|
||||
- toolset: gcc-11
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: ubuntu-20.04
|
||||
install: g++-11
|
||||
- toolset: gcc-12
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-22.04
|
||||
@@ -156,6 +141,43 @@ jobs:
|
||||
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
|
||||
@@ -214,162 +236,3 @@ jobs:
|
||||
run: |
|
||||
cd ../boost-root
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
|
||||
posix-cmake-subdir:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Use library with add_subdirectory
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
|
||||
mkdir __build__ && cd __build__
|
||||
cmake ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-install:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target install
|
||||
|
||||
- name: Use the installed library
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
|
||||
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
|
||||
cmake --build .
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
posix-cmake-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-18.04
|
||||
- os: ubuntu-20.04
|
||||
- os: ubuntu-22.04
|
||||
- os: macos-11
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
run: sudo apt install ${{matrix.install}}
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
LIBRARY=${GITHUB_REPOSITORY#*/}
|
||||
echo LIBRARY: $LIBRARY
|
||||
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
|
||||
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
|
||||
echo GITHUB_REF: $GITHUB_REF
|
||||
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
|
||||
REF=${REF#refs/heads/}
|
||||
echo REF: $REF
|
||||
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
|
||||
echo BOOST_BRANCH: $BOOST_BRANCH
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
|
||||
- name: Configure
|
||||
run: |
|
||||
cd ../boost-root
|
||||
mkdir __build__ && cd __build__
|
||||
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
|
||||
|
||||
- name: Build tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
cmake --build . --target tests
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root/__build__
|
||||
ctest --output-on-failure --no-tests=error
|
||||
|
||||
@@ -7,12 +7,30 @@ cmake_minimum_required(VERSION 3.5...3.16)
|
||||
|
||||
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||
|
||||
add_library(boost_process INTERFACE)
|
||||
add_library(boost_process
|
||||
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 INTERFACE include)
|
||||
target_include_directories(boost_process PUBLIC include)
|
||||
target_link_libraries(boost_process
|
||||
INTERFACE
|
||||
PUBLIC
|
||||
Boost::algorithm
|
||||
Boost::asio
|
||||
Boost::config
|
||||
@@ -28,9 +46,27 @@ target_link_libraries(boost_process
|
||||
Boost::winapi
|
||||
)
|
||||
|
||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||
|
||||
add_subdirectory(test)
|
||||
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()
|
||||
|
||||
|
||||
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,25 +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 : ../../.. ;
|
||||
path-constant INCLUDES : ../include ;
|
||||
|
||||
doxygen autodoc
|
||||
doxygen reference_v1
|
||||
:
|
||||
$(INCLUDES)/boost/process.hpp
|
||||
[ glob $(INCLUDES)/boost/process/*.hpp ]
|
||||
$(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=.
|
||||
@@ -60,13 +63,13 @@ doxygen reference_v2
|
||||
\"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\
|
||||
BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\
|
||||
BOOST_PROCESS_V2_DECL \\
|
||||
BOOST_PROCESS_V2_SOURCE \\
|
||||
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\
|
||||
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\
|
||||
BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\
|
||||
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\
|
||||
BOOST_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
|
||||
@@ -84,7 +87,7 @@ boostbook standalone
|
||||
:
|
||||
process.qbk
|
||||
:
|
||||
<dependency>autodoc
|
||||
<dependency>reference_v1
|
||||
<dependency>reference_v2
|
||||
<dependency>images
|
||||
<dependency>images_glob
|
||||
@@ -95,7 +98,7 @@ boostbook standalone
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: standalone/<format>docbook
|
||||
:
|
||||
:
|
||||
: <dependency>images_glob
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
|
||||
@@ -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,14 +11,8 @@
|
||||
]
|
||||
]
|
||||
|
||||
[note [link process.v2 Process V2] is available as experimental]
|
||||
[note Process v1 will be deprecated in the next release (1.88). Use v2 for new projects.]
|
||||
|
||||
[include introduction.qbk]
|
||||
[include concepts.qbk]
|
||||
[include tutorial.qbk]
|
||||
[include design.qbk]
|
||||
[include extend.qbk]
|
||||
[include faq.qbk]
|
||||
[xinclude autodoc.xml]
|
||||
[include v1.qbk]
|
||||
[include v2.qbk]
|
||||
[include acknowledgements.qbk]
|
||||
[include v2.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::process::filesystem::path`, we can do this too.
|
||||
from an external source as `boost::process::v1::filesystem::path`, we can do this too.
|
||||
|
||||
```
|
||||
boost::process::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::process::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>
|
||||
@@ -9,7 +9,7 @@ Additionally, environment can be lists separated by `:` or `;`; `environment::va
|
||||
`environment::value_view` can be used to iterate those.
|
||||
|
||||
Beyond that, the requirements on an environment are a low as possible;
|
||||
an environment is either a list of strings or a list of string-pairs. It is however recommented to use the environment types,
|
||||
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.
|
||||
@@ -20,8 +20,8 @@ To note is the `find_executable` functions, which searches in an environment for
|
||||
|
||||
std::unordered_map<environment::key, environment::value> my_env =
|
||||
{
|
||||
{"SECRET", "THIS_IS_A_TEST"}
|
||||
{"PATH", {"/bin", "/usr/bin"}
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
|
||||
auto other_exe = environment::find_executable("g++", my_env);
|
||||
@@ -35,10 +35,10 @@ 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"}
|
||||
{"SECRET", "THIS_IS_A_TEST"},
|
||||
{"PATH", {"/bin", "/usr/bin"}}
|
||||
};
|
||||
auto exe = find_executable("g++"), my_env);
|
||||
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));
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ For process v2, the interfaces is simple:
|
||||
extern asio::io_context ctx;
|
||||
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
|
||||
|
||||
Every initializer adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
|
||||
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.
|
||||
|
||||
@@ -57,7 +57,7 @@ file-handles for the subprocess.
|
||||
|
||||
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.
|
||||
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,
|
||||
@@ -73,14 +73,6 @@ Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:src Separate compilation]
|
||||
|
||||
Boost.process v2 supports separate compilation similar to other boost libraries.
|
||||
It can be achieved by defining `BOOST_PROCESS_V2_SEPARATE_COMPILATION` and including
|
||||
`<process/v2/src.hpp>` in a single compile unit.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:limit_fd Fd safe by default]
|
||||
|
||||
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
|
||||
|
||||
@@ -21,7 +21,7 @@ A launcher is invoked through the call operator.
|
||||
```
|
||||
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
|
||||
asio::io_context ctx;
|
||||
boost::system::eror_code ec;
|
||||
boost::system::error_code ec;
|
||||
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
|
||||
```
|
||||
|
||||
@@ -38,7 +38,7 @@ Alternatively, the `vfork_launcher` can report errors directly back to the paren
|
||||
Thus some calls to the initializers occur after forking from the child process.
|
||||
|
||||
```
|
||||
struct custom_initalizer
|
||||
struct custom_initializer
|
||||
{
|
||||
// functions called from the parent process:
|
||||
|
||||
@@ -47,7 +47,7 @@ Thus some calls to the initializers occur after forking from the child process.
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occured during setup or process creation
|
||||
// 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);
|
||||
@@ -56,7 +56,7 @@ Thus some calls to the initializers occur after forking from the child process.
|
||||
template<typename Launcher>
|
||||
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
|
||||
|
||||
// called for every initializer if an error occured when forking, in addtion to on_error.
|
||||
// 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);
|
||||
@@ -94,7 +94,7 @@ The launcher will close all non-whitelisted file descriptors after `on_exec_setu
|
||||
|
||||
[section:windows Windows Launchers]
|
||||
|
||||
Windows launchers are pretty streight forward, they will call the following functions on the initializer if present.
|
||||
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
|
||||
|
||||
```
|
||||
struct custom_initializer
|
||||
@@ -103,7 +103,7 @@ Windows launchers are pretty streight forward, they will call the following func
|
||||
template<typename Launcher>
|
||||
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
|
||||
|
||||
// called for every initializer if an error occured during setup or process creation
|
||||
// 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);
|
||||
|
||||
@@ -32,7 +32,7 @@ also returned from `.wait()`.
|
||||
```
|
||||
|
||||
The normal exit-code is what the subprocess returned from `main`;
|
||||
posix will however add addtional information about the process.
|
||||
posix will however add additional information about the process.
|
||||
This is called the `native_exit_code`.
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ The `.running()` function can be used to detect if the process is still active.
|
||||
|
||||
[section:signal Signalling the subprocess]
|
||||
|
||||
The parent process can signal the subprocess demaning certain actions.
|
||||
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.
|
||||
@@ -76,7 +76,7 @@ interpret as a signal to shutdown.
|
||||
|
||||
[section:execute Execute functions]
|
||||
|
||||
Process v2 provides `execute` and `async_execute` functons that can be used for managed executions.
|
||||
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
|
||||
|
||||
```
|
||||
assert(execute(process("/bin/ls", {}) == 0));
|
||||
@@ -90,7 +90,7 @@ The async version supports cancellation and will forward cancellation types as f
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::steady_timer timout{ctx, std::chrono::seconds(10)};
|
||||
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
|
||||
|
||||
asio::cancellation_signal sig;
|
||||
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
|
||||
@@ -114,7 +114,6 @@ The async version supports cancellation and will forward cancellation types as f
|
||||
if (!ec)
|
||||
sig.emit(asio::cancellation_type::terminal);
|
||||
});
|
||||
);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
@@ -12,7 +12,7 @@ automatically connected and the other side will get assigned to the child proces
|
||||
|
||||
```
|
||||
asio::io_context ctx;
|
||||
asio::readable_pipe rp;
|
||||
asio::readable_pipe rp{ctx};
|
||||
|
||||
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
|
||||
std::string output;
|
||||
@@ -23,7 +23,7 @@ automatically connected and the other side will get assigned to the child proces
|
||||
proc.wait();
|
||||
```
|
||||
|
||||
readable pipes can be assigned to `out` an `err``, while writable_pipes can be assigned to `in`.
|
||||
readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -86,4 +86,4 @@ It starts a process and connects pipes for stdin and stdout, so that the popen o
|
||||
|
||||
[endsect]
|
||||
|
||||
[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::process::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/process/filesystem.hpp>
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
|
||||
namespace bp = boost::process;
|
||||
|
||||
@@ -19,9 +19,9 @@ int main()
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
|
||||
boost::process::filesystem::path exe = "test.exe";
|
||||
boost::process::v1::filesystem::path exe = "test.exe";
|
||||
bp::system(
|
||||
boost::process::filesystem::absolute(exe),
|
||||
boost::process::v1::filesystem::absolute(exe),
|
||||
bp::start_dir="../foo"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,12 @@
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project : requirements
|
||||
<include>../../..
|
||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<link>static
|
||||
;
|
||||
|
||||
import testing ;
|
||||
|
||||
alias filesystem : /boost//filesystem : <link>static ;
|
||||
|
||||
exe intro : intro.cpp filesystem ;
|
||||
exe intro_popen : intro_popen.cpp filesystem ;
|
||||
exe intro : intro.cpp ;
|
||||
exe intro_popen : intro_popen.cpp : <boost.process.fs>boost ;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
// 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)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2022Klemens Morgernstern
|
||||
// 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)
|
||||
|
||||
@@ -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/extend.hpp>
|
||||
#include <boost/process/windows.hpp>
|
||||
#include <boost/process/v1/extend.hpp>
|
||||
#include <boost/process/v1/windows.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
@@ -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 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::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,151 +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 Handler>
|
||||
struct async_system_handler : ::boost::process::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::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::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
|
||||
|
||||
#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,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,503 +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/detail/traits/wchar_t.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,711 +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/process/filesystem.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)
|
||||
{
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
break;
|
||||
p++;
|
||||
}
|
||||
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)
|
||||
{
|
||||
const int len = std::char_traits<Char>::length(*p);
|
||||
if ((std::distance(st1.begin(), st1.end()) < len)
|
||||
&& std::equal(st1.begin(), st1.end(), *p))
|
||||
return 1u;
|
||||
p++;
|
||||
}
|
||||
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::process::filesystem::path> path()
|
||||
{
|
||||
#if defined(BOOST_WINDOWS_API)
|
||||
const ::boost::process::wnative_environment ne{};
|
||||
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
|
||||
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::process::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::process::filesystem::path::value_type> operator()(const boost::process::filesystem::path & pth) const
|
||||
{
|
||||
return exe_setter_<typename boost::process::filesystem::path::value_type>(pth.native());
|
||||
}
|
||||
|
||||
template<typename = void>
|
||||
inline exe_setter_<typename boost::process::filesystem::path::value_type> operator=(const boost::process::filesystem::path & pth) const
|
||||
{
|
||||
return exe_setter_<typename boost::process::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::process::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,344 +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>
|
||||
#include <memory>
|
||||
|
||||
#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>
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
// Copyright (c) 2021 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_FILESYSTEM_HPP
|
||||
#define BOOST_PROCESS_FILESYSTEM_HPP
|
||||
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
#include <filesystem>
|
||||
#else
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
#ifdef BOOST_PROCESS_USE_STD_FS
|
||||
namespace filesystem = std::filesystem;
|
||||
#else
|
||||
namespace filesystem = boost::filesystem;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BOOST_PROCESS_FILESYSTEM_HPP
|
||||
#include <boost/config/header_deprecated.hpp>
|
||||
BOOST_HEADER_DEPRECATED("<boost/process/v1/filesystem.hpp>")
|
||||
#include <boost/process/v1/filesystem.hpp>
|
||||
|
||||
@@ -1,233 +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);
|
||||
}
|
||||
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
|
||||
/** Wait for the process group to exit for period of time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time);
|
||||
}
|
||||
|
||||
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
|
||||
template< class Rep, class Period >
|
||||
BOOST_DEPRECATED("wait_for is unreliable")
|
||||
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
|
||||
}
|
||||
|
||||
/** Wait for the process group to exit until a point in time.
|
||||
* \return True if all child processes exited while waiting.*/
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
|
||||
}
|
||||
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
|
||||
template< class Clock, class Duration >
|
||||
BOOST_DEPRECATED("wait_until is unreliable")
|
||||
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
|
||||
{
|
||||
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
|
||||
}
|
||||
#endif
|
||||
///Check if the group has a valid handle.
|
||||
bool valid() const
|
||||
{
|
||||
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::process::filesystem::path log = "my_log_file.txt";
|
||||
boost::process::filesystem::path input = "input.txt";
|
||||
boost::process::filesystem::path output = "output.txt";
|
||||
system("my_prog", std_out>output, std_in<input, std_err>log);
|
||||
\endcode
|
||||
|
||||
\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::process::filesystem::path &p) const {return p;}
|
||||
api::file_in operator=(const std::string & p) const {return p;}
|
||||
api::file_in operator=(const std::wstring &p) const {return p;}
|
||||
api::file_in operator=(const char * p) const {return p;}
|
||||
api::file_in operator=(const wchar_t * p) const {return p;}
|
||||
|
||||
api::file_in operator<(const boost::process::filesystem::path &p) const {return p;}
|
||||
api::file_in operator<(const std::string &p) const {return p;}
|
||||
api::file_in operator<(const std::wstring &p) const {return p;}
|
||||
api::file_in operator<(const char*p) const {return p;}
|
||||
api::file_in operator<(const wchar_t * p) const {return p;}
|
||||
|
||||
api::file_in operator=(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::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
api::file_out<p1,p2> operator>(const boost::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
|
||||
api::file_out<p1,p2> operator>(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
|
||||
|
||||
api::file_out<p1,p2> operator=(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::process::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::process::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,245 +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
|
||||
// Return a default locale object.
|
||||
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(static_cast<int>(-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::process::filesystem::path search_path(const boost::process::filesystem::path &filename,
|
||||
const std::vector<boost::process::filesystem::path> path = ::boost::this_process::path())
|
||||
{
|
||||
return ::boost::process::detail::api::search_path(filename, path);
|
||||
}
|
||||
}}
|
||||
|
||||
#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::process::filesystem::path operator()() const
|
||||
{
|
||||
return boost::process::detail::api::shell_path();
|
||||
}
|
||||
boost::process::filesystem::path operator()(std::error_code & ec) const noexcept
|
||||
{
|
||||
return boost::process::detail::api::shell_path(ec);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_wchar_t<shell_> : is_wchar_t<boost::process::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/process/filesystem.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::process::filesystem::path::value_type>
|
||||
operator()(const boost::process::filesystem::path & st) const {return {st.native()}; }
|
||||
|
||||
template<typename Char>
|
||||
api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; }
|
||||
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::process::filesystem::path::value_type>
|
||||
operator= (const boost::process::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::process::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::process::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,36 +25,36 @@
|
||||
#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) {}
|
||||
@@ -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,14 +115,14 @@ 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)
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
{
|
||||
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
|
||||
@@ -154,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);
|
||||
|
||||
@@ -166,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;
|
||||
@@ -177,7 +177,7 @@ 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);
|
||||
}
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
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);
|
||||
@@ -225,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();
|
||||
@@ -117,5 +133,7 @@ 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
|
||||
{
|
||||
@@ -37,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]);
|
||||
@@ -205,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);
|
||||
@@ -236,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)
|
||||
@@ -245,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()");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,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)
|
||||
@@ -272,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);
|
||||
@@ -304,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)
|
||||
@@ -313,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};
|
||||
@@ -360,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
|
||||
@@ -172,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/process/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;
|
||||
while ((read_len = static_cast<int_type>(::read(_source, data, count * sizeof(char_type)))) == -1)
|
||||
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;
|
||||
@@ -68,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;
|
||||
@@ -114,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();
|
||||
}
|
||||
|
||||
@@ -186,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);
|
||||
}
|
||||
|
||||
);
|
||||
@@ -202,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;
|
||||
@@ -230,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())
|
||||
@@ -250,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())
|
||||
@@ -261,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();
|
||||
@@ -270,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())
|
||||
@@ -280,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();
|
||||
|
||||
|
||||
@@ -320,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>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#include <boost/core/ignore_unused.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 Executor>
|
||||
struct on_setup_t
|
||||
@@ -204,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_ );
|
||||
@@ -349,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();
|
||||
}
|
||||
@@ -357,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);
|
||||
}
|
||||
@@ -389,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();
|
||||
}
|
||||
|
||||
@@ -413,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));
|
||||
|
||||
@@ -439,12 +443,13 @@ 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 occured we need to reap the child process
|
||||
//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();
|
||||
@@ -475,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();
|
||||
}
|
||||
@@ -483,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);
|
||||
}
|
||||
@@ -511,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));
|
||||
@@ -524,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));
|
||||
|
||||
@@ -563,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,10 +8,10 @@
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string>
|
||||
#include <boost/process/filesystem.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
|
||||
{
|
||||
@@ -24,7 +24,7 @@ struct file_descriptor
|
||||
|
||||
|
||||
file_descriptor() = default;
|
||||
explicit file_descriptor(const boost::process::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)
|
||||
{
|
||||
}
|
||||
@@ -84,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
|
||||
@@ -6,12 +6,12 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#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 group_handle
|
||||
{
|
||||
@@ -70,7 +70,7 @@ struct group_handle
|
||||
inline void terminate(group_handle &p, std::error_code &ec) noexcept
|
||||
{
|
||||
if (::killpg(p.grp, SIGKILL) == -1)
|
||||
ec = boost::process::detail::get_last_error();
|
||||
ec = boost::process::v1::detail::get_last_error();
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
@@ -81,7 +81,7 @@ inline void terminate(group_handle &p)
|
||||
{
|
||||
std::error_code ec;
|
||||
terminate(p, ec);
|
||||
boost::process::detail::throw_error(ec, "killpg(2) failed in terminate");
|
||||
boost::process::v1::detail::throw_error(ec, "killpg(2) failed in terminate");
|
||||
}
|
||||
|
||||
inline bool in_group()
|
||||
@@ -89,6 +89,6 @@ inline bool in_group()
|
||||
return true;
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */
|
||||
@@ -6,13 +6,13 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/group_handle.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/group_handle.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
namespace boost { namespace process {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 {
|
||||
|
||||
namespace detail { namespace posix {
|
||||
|
||||
@@ -46,7 +46,7 @@ struct group_ref : handler_base_ext
|
||||
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
|
||||
#endif /* BOOST_PROCESS_DETAIL_POSIX_GROUP_REF_HPP_ */
|
||||
@@ -6,9 +6,9 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_HANDLER_HPP_
|
||||
|
||||
#include <boost/process/detail/handler_base.hpp>
|
||||
#include <boost/process/v1/detail/handler_base.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
//does not extend anything.
|
||||
struct handler_base_ext : handler_base
|
||||
@@ -67,7 +67,7 @@ private:
|
||||
Handler handler_;
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
|
||||
using native_handle_type = int;
|
||||
@@ -27,13 +27,13 @@ inline std::vector<native_handle_type> get_handles(std::error_code & ec)
|
||||
std::unique_ptr<DIR, void(*)(DIR*)> dir{::opendir("/dev/fd"), +[](DIR* p){::closedir(p);}};
|
||||
if (!dir)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return {};
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
|
||||
auto my_fd = ::dirfd(dir.get());
|
||||
auto my_fd = dirfd(dir.get());
|
||||
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
@@ -60,7 +60,7 @@ inline std::vector<native_handle_type> get_handles()
|
||||
|
||||
auto res = get_handles(ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
|
||||
boost::process::v1::detail::throw_error(ec, "open_dir(\"/dev/fd\") failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -72,7 +72,7 @@ inline bool is_stream_handle(native_handle_type handle, std::error_code & ec)
|
||||
|
||||
if (::fstat(handle, &stat_) != 0)
|
||||
{
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
}
|
||||
else
|
||||
ec.clear();
|
||||
@@ -90,7 +90,7 @@ inline bool is_stream_handle(native_handle_type handle)
|
||||
std::error_code ec;
|
||||
auto res = is_stream_handle(handle, ec);
|
||||
if (ec)
|
||||
boost::process::detail::throw_error(ec, "fstat() failed");
|
||||
boost::process::v1::detail::throw_error(ec, "fstat() failed");
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -113,11 +113,11 @@ struct limit_handles_ : handler_base_ext
|
||||
auto dir = ::opendir("/dev/fd");
|
||||
if (!dir)
|
||||
{
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "opendir(\"/dev/fd\")");
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "opendir(\"/dev/fd\")");
|
||||
return;
|
||||
}
|
||||
|
||||
auto my_fd = ::dirfd(dir);
|
||||
auto my_fd = dirfd(dir);
|
||||
struct ::dirent * ent_p;
|
||||
|
||||
while ((ent_p = readdir(dir)) != nullptr)
|
||||
@@ -135,7 +135,7 @@ struct limit_handles_ : handler_base_ext
|
||||
|
||||
if (::close(conv) != 0)
|
||||
{
|
||||
exec.set_error(::boost::process::detail::get_last_error(), "close() failed");
|
||||
exec.set_error(::boost::process::v1::detail::get_last_error(), "close() failed");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -143,6 +143,6 @@ struct limit_handles_ : handler_base_ext
|
||||
}
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif //PROCESS_HANDLES_HPP
|
||||
@@ -6,8 +6,8 @@
|
||||
#ifndef BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
|
||||
#define BOOST_PROCESS_POSIX_IO_CONTEXT_REF_HPP_
|
||||
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/async_handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/async_handler.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include <boost/fusion/algorithm/iteration/for_each.hpp>
|
||||
@@ -17,8 +17,8 @@
|
||||
#include <boost/fusion/container/vector/convert.hpp>
|
||||
|
||||
|
||||
#include <boost/process/detail/posix/sigchld_service.hpp>
|
||||
#include <boost/process/detail/posix/is_running.hpp>
|
||||
#include <boost/process/v1/detail/posix/sigchld_service.hpp>
|
||||
#include <boost/process/v1/detail/posix/is_running.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <vector>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
template<typename Executor>
|
||||
struct on_exit_handler_transformer
|
||||
@@ -80,7 +80,7 @@ struct io_context_ref : handler_base_ext
|
||||
void on_success(Executor& exec)
|
||||
{
|
||||
ios.notify_fork(boost::asio::io_context::fork_parent);
|
||||
//must be on the heap so I can move it into the lambda.
|
||||
//must be on the heap, so I can move it into the lambda.
|
||||
auto asyncs = boost::fusion::filter_if<
|
||||
is_async_handler<
|
||||
typename std::remove_reference< boost::mpl::_ > ::type
|
||||
@@ -100,7 +100,7 @@ struct io_context_ref : handler_base_ext
|
||||
{
|
||||
es->store(val);
|
||||
for (auto & func : funcs)
|
||||
func(::boost::process::detail::posix::eval_exit_status(val), ec);
|
||||
func(::boost::process::v1::detail::posix::eval_exit_status(val), ec);
|
||||
};
|
||||
|
||||
sigchld_service.async_wait(exec.pid, std::move(wh));
|
||||
@@ -117,9 +117,9 @@ struct io_context_ref : handler_base_ext
|
||||
|
||||
private:
|
||||
boost::asio::io_context &ios;
|
||||
boost::process::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::detail::posix::sigchld_service>(ios);
|
||||
boost::process::v1::detail::posix::sigchld_service &sigchld_service = boost::asio::use_service<boost::process::v1::detail::posix::sigchld_service>(ios);
|
||||
};
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif /* BOOST_PROCESS_WINDOWS_IO_CONTEXT_REF_HPP_ */
|
||||
@@ -6,12 +6,12 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_IS_RUNNING_HPP
|
||||
|
||||
#include <boost/process/detail/config.hpp>
|
||||
#include <boost/process/detail/posix/child_handle.hpp>
|
||||
#include <boost/process/v1/detail/config.hpp>
|
||||
#include <boost/process/v1/detail/posix/child_handle.hpp>
|
||||
#include <system_error>
|
||||
#include <sys/wait.h>
|
||||
|
||||
namespace boost { namespace process { namespace detail { namespace posix {
|
||||
namespace boost { namespace process { BOOST_PROCESS_V1_INLINE namespace v1 { namespace detail { namespace posix {
|
||||
|
||||
// Use the "stopped" state (WIFSTOPPED) to indicate "not terminated".
|
||||
// This bit arrangement of status codes is not guaranteed by POSIX, but (according to comments in
|
||||
@@ -34,8 +34,8 @@ inline bool is_running(const child_handle &p, int & exit_code, std::error_code &
|
||||
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno != ECHILD) //because it no child is running, than this one isn't either, obviously.
|
||||
ec = ::boost::process::detail::get_last_error();
|
||||
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
|
||||
ec = ::boost::process::v1::detail::get_last_error();
|
||||
return false;
|
||||
}
|
||||
else if (ret == 0)
|
||||
@@ -55,7 +55,7 @@ inline bool is_running(const child_handle &p, int & exit_code)
|
||||
{
|
||||
std::error_code ec;
|
||||
bool b = is_running(p, exit_code, ec);
|
||||
boost::process::detail::throw_error(ec, "waitpid(2) failed in is_running");
|
||||
boost::process::v1::detail::throw_error(ec, "waitpid(2) failed in is_running");
|
||||
return b;
|
||||
}
|
||||
|
||||
@@ -75,6 +75,6 @@ inline int eval_exit_status(int code)
|
||||
}
|
||||
}
|
||||
|
||||
}}}}
|
||||
}}}}}
|
||||
|
||||
#endif
|
||||
@@ -10,16 +10,16 @@
|
||||
#ifndef BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
#define BOOST_PROCESS_DETAIL_POSIX_NULL_IN_HPP
|
||||
|
||||
#include <boost/process/pipe.hpp>
|
||||
#include <boost/process/detail/posix/handler.hpp>
|
||||
#include <boost/process/detail/posix/file_descriptor.hpp>
|
||||
#include <boost/process/v1/pipe.hpp>
|
||||
#include <boost/process/v1/detail/posix/handler.hpp>
|
||||
#include <boost/process/v1/detail/posix/file_descriptor.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 null_in : handler_base_ext, ::boost::process::detail::uses_handles
|
||||
struct null_in : handler_base_ext, ::boost::process::v1::detail::uses_handles
|
||||
{
|
||||
file_descriptor source{"/dev/null", file_descriptor::read};
|
||||
|
||||
@@ -34,10 +34,10 @@ public:
|
||||
void on_exec_setup(Executor &e) const
|
||||
{
|
||||
if (::dup2(source.handle(), STDIN_FILENO) == -1)
|
||||
e.set_error(::boost::process::detail::get_last_error(), "dup2() failed");
|
||||
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