2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-20 16:52:14 +00:00

Compare commits

...

226 Commits

Author SHA1 Message Date
Klemens Morgenstern
13c4b0aa14 added wait_pid to be run in set_error. 2023-10-05 10:51:24 +08:00
AJIOB
b9fc531507 Code typos fix 2023-10-05 09:36:50 +08:00
Klemens Morgenstern
69c2c25729 added SIGTERM bit mask for freeBSD. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
8ab2332327 v2/env win test fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
ea69cda6d8 added can_interrupt check on windows to win tests. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
6b75b4039f increased timeout & added diagnostics. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
3c1beb40f6 windows move handle fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
e51970e3bb fixed windows interrupt & request_exit test. 2023-10-05 06:52:20 +08:00
Klemens
f3f8548dea allowing for SIGTERM in exit code on posix interrupts. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
4b7a00d4cf target: global timer workaround helper. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
c11f31d77e drone windows update. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
3769ec01f4 process native-exit code test. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
af47f4677c creation-flags fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
cf14d54343 pid no-access workarounds. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
b81cac8042 moved interrupt & request_exit into target. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
c92cce3652 cmd.ipp return fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
d270712fba link error fix. 2023-10-05 06:52:20 +08:00
Klemens Morgenstern
7b6b93691f fixed executor reset_cancellation_state.
Closes #338.
2023-10-05 06:52:20 +08:00
Shauren
507768e230 Fixed compile warning on msvc 2023-09-14 08:09:35 +08:00
SilverPlate3
502dc48753 Pass empty argument
closes #256
2023-08-14 17:47:17 +08:00
Ed Tanous
402acc151a Use boost::throw_exception
Using boost::throw_exception allows for modifications to these
exceptions on a per-application basis, including overriding with custom
implementations.

This also has the benefit of allowing compilation with -fno-exceptions
set, which should make this code more portable.
2023-08-14 17:41:37 +08:00
Roberto Rodriguez
0503b0997c Fix compilation with -Wall and -Werror 2023-08-14 17:41:00 +08:00
Klemens Morgenstern
8d372cb510 v2::environment link fixes 2023-08-14 17:28:54 +08:00
Klemens Morgenstern
bfb1ebb5bd Merge branch 'master' into develop
# Conflicts:
#	.github/workflows/ci.yml
#	include/boost/process/environment.hpp
#	include/boost/process/v2/exit_code.hpp
#	include/boost/process/v2/ext/cmd.hpp
#	include/boost/process/v2/ext/cwd.hpp
#	include/boost/process/v2/ext/env.hpp
#	include/boost/process/v2/ext/exe.hpp
#	test/v2/pid.cpp
#	test/v2/process.cpp
2023-06-28 20:30:30 +08:00
Klemens Morgenstern
c005adc8fc simplified stdio. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
5cab462710 added empty env var check to tests. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
ccd46dc692 added Bcrypt to gcc win builds. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
b3c8c3a8da fixed popen test. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
4dd6f28094 removed code_as_error. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
d73f228469 popen test adjustements. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
ccd1717588 test updates for CI 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
9a4aeab97e simplified terminate test. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
d66dce11bd ext/*.hpp order fix 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
fc38699a4b terminate test logs ec. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
a859c5151c removed posix-cmake-subdir from github actions. 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
8c2f403841 posix::basic_cmd handles empty cmd
closes #304.
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
6fb2702a79 fixed unsigned & signed warnings
closes #301
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
6cd4244f05 doc typo fixes 2023-06-28 20:24:12 +08:00
Klemens Morgenstern
0c42a58eac ~pipe_buf catches exceptions from overflow
Closes #111
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
f269236d38 vfork launcher fixes
closes #314
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
4b413d34f4 Remove initializer_list<wstring_view> constructors.
They are causing ambiguity and are not that useful.

Closes #313
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
1403af769b process uses v2::detail::throw_error
closes #318
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
964f6d3f7e pipe_* includes error_code
closes #316
2023-06-28 20:24:12 +08:00
Klemens Morgenstern
bccf42a3ec include fix for v2/environment.hpp. 2023-06-28 20:24:12 +08:00
nikola-sh
70c7ae694f Fix MSVC compile errors 2023-06-13 20:44:03 +08:00
Klemens Morgenstern
1fdd405a3f More typo fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
af2e884352 Typo fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
1fbd8bb5e1 handle_info include fix for handles.hpp. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
09ba5e8d47 Reduced amount of test & fixed path comparisons. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
2c6304b563 pid_test fixes for osx. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
e79c5f5edd Updated pid test. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
7a9ab79162 removed noexcept from env v2 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
0c1c6dfa90 sighchld service & test fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
4f9f4c398a close #296. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
e4a3e305b4 ec use locations. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
9d51e1cd32 xproc fixes 2023-02-22 22:46:07 +08:00
Samuel Venable
f1302430cb extern process management. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
6f0d6a2e24 switched to BOOST_DEPRECATED. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
57b67e0173 added clang 3.8. noexcept deduction. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
bbc7eb82e5 disabled terminate test for freebsd. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
744e9d95b3 [drone] Removed mlocate dep. 2023-02-22 22:46:07 +08:00
Ivan Efimov
bc9a98787e Fix string construction in native_environment_impl::get 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
0fdd448c67 Deprecated wait_for & wait_until. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
5fcf5465ce Switched vector in list of sigclhd_service.
Closes #175
2023-02-22 22:46:07 +08:00
Gary Miguel
1dc9d8689e fix error message 2023-02-22 22:46:07 +08:00
Klemens
dc915be11d ec fix for search_path with std::filesystem.
closes #287.
2023-02-22 22:46:07 +08:00
Orgad Shaneh
d7df60938e Fix crash on search_path on Windows when PATHEXT is not found 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
765650aed3 Update process.cpp 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
f12bc25122 Disabled some tests for freebsd & added interrupt handling to osx test. 2023-02-22 22:46:07 +08:00
sdarwin
32a2c2297c Update metadata 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
3258e3a11c Typo fix. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
ba7e8db9bb Include fixes. 2023-02-22 22:46:07 +08:00
Klemens Morgenstern
3211afda4a More typo fixes. 2023-02-22 13:04:13 +08:00
Klemens Morgenstern
d3f006acd4 Typo fixes. 2023-02-22 13:01:46 +08:00
Klemens Morgenstern
99633a6e42 handle_info include fix for handles.hpp. 2023-02-22 12:26:31 +08:00
Klemens Morgenstern
1e614ee43e Reduced amount of test & fixed path comparisons. 2023-02-22 00:54:17 +08:00
Klemens Morgenstern
0e3358705d pid_test fixes for osx. 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
27a35f452d Updated pid test. 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
8fff7283ed removed noexcept from env v2 2023-02-21 16:27:40 +08:00
Klemens Morgenstern
611dac143f sighchld service & test fixes. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
8d93576b94 close #296. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
f703845011 ec use locations. 2023-02-20 14:09:38 +08:00
Klemens Morgenstern
abd052e09f xproc fixes 2023-02-20 14:09:38 +08:00
Samuel Venable
a3304564c6 extern process management. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
5865c6b449 switched to BOOST_DEPRECATED. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
4c872c0a0d added clang 3.8. noexcept deduction. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
feabbee098 disabled terminate test for freebsd. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
a5b6e70c39 [drone] Removed mlocate dep. 2023-02-20 14:09:37 +08:00
Ivan Efimov
347fc68476 Fix string construction in native_environment_impl::get 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
61ff12c8da Deprecated wait_for & wait_until. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
bd8e81153c Switched vector in list of sigclhd_service.
Closes #175
2023-02-20 14:09:37 +08:00
Gary Miguel
5fde6bec9f fix error message 2023-02-20 14:09:37 +08:00
Klemens
cf64f7dc6a ec fix for search_path with std::filesystem.
closes #287.
2023-02-20 14:09:37 +08:00
Orgad Shaneh
8355c3e1b6 Fix crash on search_path on Windows when PATHEXT is not found 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
de797e388d Update process.cpp 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
fc33435f8b Disabled some tests for freebsd & added interrupt handling to osx test. 2023-02-20 14:09:37 +08:00
sdarwin
f45ec624db Update metadata 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
9682056278 Typo fix. 2023-02-20 14:09:37 +08:00
Klemens Morgenstern
a00115b454 Include fixes. 2023-02-20 14:09:37 +08:00
Sam Darwin
3db86ac69f Drone: update freebsd jobs (#274) 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
5ffb6bf8da using scope-exit limit group_wait. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2c5a38bfbe Disabled limit_fd for freebsd. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
f28a6406ae group wait test on_scope exit fix. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
7a1820d546 Disabled pdfork by default, bc of asio errors. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
6bc5add9a7 Increased timeout for sporadically failing test. 2022-11-01 19:41:20 +08:00
Alexander Grund
f876ba81e6 Update .drone.star
Remove the `image` param which is superflous, misleading and may become an error. See https://github.com/boostorg/boost-ci/pull/189

[skip ci]
2022-11-01 19:41:20 +08:00
Klemens Morgenstern
e943f8fb9c Improved error message for OSX. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
bc55a93dce passing a pipe into sh test. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2eee42d5e6 Added return_type to async_result<code_as_error_t> 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2d2b124647 Minor bugfixes 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
50986cc330 Enabled freebsd build 2022-11-01 19:41:20 +08:00
Klemens
09f0a2c547 Fixed async_system. 2022-11-01 19:41:20 +08:00
Klemens
13af16bfec Added bind_launcher. 2022-11-01 19:41:20 +08:00
Klemens
7745fdc687 Added code_as_error completion handler. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
d36f481392 Added WIN32_LEAN_AND_MEAN to cmake 2022-11-01 19:41:20 +08:00
Klemens
011380c28a Shell(posix) fixes. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ebd4e723c3 Exeuction support for shell. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
b8108c508f Implemented shell on windows. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ecf3dde88c Windows bugfixes. 2022-11-01 19:41:20 +08:00
Klemens
4761b375d0 Added shell class. 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
ae6a9e6639 Closes #267 2022-11-01 19:41:20 +08:00
Klemens Morgenstern
2c35167d9b Closes #266 2022-11-01 19:41:20 +08:00
Klemens
b68900ca1c Fixed unsafe post-fork allocs for fd_whitelist. 2022-11-01 19:41:20 +08:00
Klemens
ba7fe11193 Added reaping child for execve error, closes #265. 2022-11-01 19:41:20 +08:00
grtowel1510f
b0da4ad10c fix issue #251 - fix simple shell command in posix
see issue #251 for description.
2022-11-01 19:41:20 +08:00
Klemens
c1b6eb4eb8 Merge branch 'develop' 2022-08-19 00:04:30 +08:00
Klemens
4ef1792b0a Typo fix. 2022-08-19 00:04:16 +08:00
Klemens
1a6956134a Merge branch 'develop' 2022-08-19 00:01:33 +08:00
Klemens Morgenstern
eb6bce0910 Merge pull request #264 from hebasto/220802-mingw
Fix compiling for MinGW-w64 using std::filesystem
2022-08-18 23:57:10 +08:00
Klemens
9a1c6991c9 Fixed cmake build 2022-08-18 22:02:33 +08:00
Klemens
352b6cf89f Added github action yml 2022-08-18 21:17:42 +08:00
Klemens
317b1b7c62 Added Boost::process to link_libraries in CMake. 2022-08-17 18:12:55 +08:00
Hennadii Stepanov
a7b65bfc44 Fix compiling for MinGW-w64 using std::filesystem 2022-08-02 09:36:44 +01:00
Klemens Morgenstern
ee945a6b95 Merge pull request #262 from boostorg/develop
Master update 1.80
2022-06-24 01:23:56 +08:00
Klemens Morgenstern
992de7b6ea Merge pull request #261 from boostorg/develop-merge
Master update 1.80
2022-06-23 10:30:01 +08:00
Klemens Morgenstern
6e597b5c8a Merge branch 'master' into develop-merge 2022-06-20 02:38:26 +08:00
Klemens
1a1d677d76 Closes #202 2022-06-11 15:00:32 +08:00
Klemens
c1fb7758b2 Added missing incldue 2022-06-11 13:25:27 +08:00
Klemens Morgenstern
e24af699cf Merge pull request #257 from boostorg/v2
V2
2022-06-11 13:15:49 +08:00
Klemens
e585864cf4 Changed default whitelist to stdio 2022-06-11 12:17:36 +08:00
Klemens
69a0615530 Fixed times in test 2022-06-10 22:04:01 +08:00
Klemens
26f4584e1e Increased wait time for group_wait 2022-06-10 19:52:41 +08:00
Klemens
43e845a691 Fixed execute_op error 2022-06-08 14:58:06 +08:00
Klemens
4d59330067 Added EINTR handling for OSX 2022-06-07 12:06:33 +08:00
Klemens
f59c1c180e Removed asserts around printf. 2022-06-07 11:38:03 +08:00
Klemens
618c931188 Added more additional diagnostics to test 2022-06-07 11:16:09 +08:00
Klemens
727881649c Typo fixes 2022-06-07 10:17:23 +08:00
Klemens
dd4bf8d857 Debugging env 2022-06-07 00:56:03 +08:00
Klemens
9d006cdd94 Improved environment tests to not drop other vars 2022-06-07 00:19:34 +08:00
Klemens
442a6ed8d8 Fixed fork_parent 2022-06-06 23:48:35 +08:00
Klemens
686945f46f Fixed signal completion. 2022-06-06 13:32:48 +08:00
Klemens
8979836f32 Added BOOST_TEST_IGNORE_SIGCHLD 2022-06-06 01:19:39 +08:00
Klemens
4dfc1bd4fd Fixed waitpid in the async_wait 2022-06-05 22:00:36 +08:00
Klemens
f90edf44e1 temporarily ignoring close_all_fds for diagnostics 2022-06-05 20:45:20 +08:00
Klemens
f56e42fd2e Added diagnostic for CI 2022-06-05 18:24:01 +08:00
Klemens
b9420be981 removed usin ""s 2022-06-05 17:47:37 +08:00
Klemens
548ea7d999 Process env test fixes 2022-06-05 16:54:52 +08:00
Klemens
f453d93e83 Set pth in env test to absolute 2022-06-05 16:09:24 +08:00
Klemens
693a33010d Added more logs to tests 2022-06-05 15:59:09 +08:00
Klemens
faad3fa4df More fixes 2022-06-05 15:36:04 +08:00
Klemens
4e2e580b4c Multiple non-linux fixes 2022-06-05 14:58:00 +08:00
Klemens
d60ea9c4d3 environ fix for apple 2022-06-05 02:39:41 +08:00
Klemens
a911da2c1f More CI-driven test fixes 2022-06-05 02:35:49 +08:00
Klemens
f0c98aa97f Multiple fixes 2022-06-05 02:11:24 +08:00
Klemens
062ac9beb2 Added limit_fd functionality 2022-06-05 01:55:28 +08:00
Klemens
fb48747fc8 Another cstring_ref 2022-06-04 23:26:14 +08:00
Klemens
f2a0367605 Minor buf fixes 2022-06-04 23:00:13 +08:00
Klemens
3163496b70 Added documentation 2022-06-04 21:19:40 +08:00
Klemens
4e64224ef1 Starlark fix & added alias for subdirector 2022-06-04 17:21:28 +08:00
Klemens
25669a78de Removed superfluous builds 2022-06-04 16:59:40 +08:00
Klemens
910192e2ad Added reference doc for v2. 2022-06-04 16:44:57 +08:00
Klemens
15984e3288 Enabled freebsd 2022-06-04 12:40:41 +08:00
Klemens
6aa704c208 Added comments 2022-06-04 12:35:20 +08:00
Klemens
62d40caddd Added sleep test. 2022-06-03 11:54:34 +08:00
Klemens
d63d502b40 Added v2 examples and some doc comments. 2022-06-03 11:03:30 +08:00
Klemens Morgenstern
3a401dd306 Merge pull request #253 from Flamefire/patch-1
Remove superflous calls in CMakeLists
2022-06-03 01:05:51 +08:00
Klemens
3893a96c6e Added hashs for environment. 2022-06-02 04:01:24 +08:00
Klemens
76c393fb8e Added execute & async_execute. 2022-06-01 16:07:38 +08:00
Klemens
4fce3c8184 Added popen. 2022-06-01 14:51:56 +08:00
Klemens
54b698dcbd Added special treatment for pipes in stdio. 2022-06-01 13:48:51 +08:00
Klemens
1f45677518 Added exit-code error category. 2022-06-01 12:43:57 +08:00
Klemens
1493e365ed FreeBSD fixes. 2022-05-31 13:24:36 +08:00
Klemens
5e5e0b8641 Minor doc additions. 2022-05-31 12:55:14 +08:00
Klemens Morgenstern
932ac3038e Added tests for windows extra launchers. 2022-05-31 10:29:39 +08:00
Klemens Morgenstern
00bc1ccf47 Fixed windows extra launchers. 2022-05-30 11:47:58 +08:00
Klemens
257da990d5 Added pidfd_open impl for linux. 2022-05-30 01:41:20 +08:00
Klemens Morgenstern
c6a812e401 Added test & fixed some found bugs. 2022-05-29 14:51:44 +08:00
Klemens Morgenstern
f93290d3d4 Completed windows port to v2 from asio. 2022-05-29 02:38:37 +08:00
Klemens
a46ab25046 Added utf8 on linux. 2022-05-26 16:58:20 +08:00
Klemens Morgenstern
1b61ba6ea7 Fixed InputIt overlaods. 2022-05-26 15:59:49 +08:00
Klemens Morgenstern
27f79e1774 Added missing files. 2022-05-26 15:54:21 +08:00
Klemens Morgenstern
0fbfa1cdc1 Switched to pure utf8 support on windows. 2022-05-26 15:01:01 +08:00
Alexander Grund
47c4496d05 Remove superflous calls in CMakeLists
The find_package is not required, as the dependencies are done using the superproject build
The include_directories is already there: target_include_directories
2022-05-23 16:12:28 +02:00
Klemens Morgenstern
c473251709 Added windows environment stuff. 2022-05-20 12:25:32 +08:00
Klemens
7bdf11f550 Added posix first environment draft. 2022-05-20 01:52:48 +08:00
Klemens
dbcc946dac Added early return for empty input. 2022-05-19 19:24:03 +08:00
Klemens
e0e801cbb4 Added the pid get_id function and pid_type type alias. 2022-05-19 19:24:03 +08:00
Klemens
4943c74e8e First steps for v2
- Added utility functions
 - cstring_ref
 - codecvt functions
2022-05-19 19:24:01 +08:00
Klemens
0733217423 Added boost_process_ prefix to test/CMakeFiles.txt. 2022-05-19 19:20:53 +08:00
Klemens
397e685053 Updated readme. 2022-05-19 17:20:36 +08:00
Klemens Morgenstern
610b337fa3 Drone & Multple fix (#250)
Squash after invalid branch & merge conflict.

* Fixed file_descriptor move assignment operator to return a reference to 'this'. Issue # 219

* Returning *this instead of erroneous *this. Issue # 219

* Removed unneeded WNOHANG.

* Closes boostorg/process#190

* Closes boostorg/process#121

* Attempting to fix wchar_t build error on circle.

* Closes boostorg/process#197.

* Changed child(pid_t) signature.

* Multiple fixes.

* Closes boostorg/process#189.

* Closes boostorg/process#191.

* Added missing work guard on windows.

* Trying to catch windows early complete.

* Increased log level on windows.

* Multiple windows test fixes

* Removed overly constraint tests.

* fix missing headers

* Closes klemens-morgenstern/boost-process#218

* Update executor.hpp

explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`

* Fix posix implementation of move constructor/assignment in file_descriptor

* Adjust docs `@boost` relative paths

* Fixed UB for large environment names.

* Closes boostorg/process#207.

* Drone setup

* Added include for filesystem::fstream.

* Disabled useless tests.

* Fixed environment length checks.

* Pipe test & warning fixes.

* Disabled warnings & added windows include fix.

* More test fixes.

* Removed some tests from apple build.

* Removed some tests from apple build.

* Disabled OSX tests via build script & fixed windows examples.

* TSA fix attempt.

Co-authored-by: James Baker <james.baker@bullochtech.com>
Co-authored-by: silent <silent@symica.com>
Co-authored-by: ikrijan <62850248+ikrijan@users.noreply.github.com>
Co-authored-by: Shauren <shauren.trinity@gmail.com>
Co-authored-by: alandefreitas <alandefreitas@gmail.com>
2022-05-19 17:00:15 +08:00
Klemens Morgenstern
bbb7dced5c Merge pull request #245 from hgkjshegfskef/develop
Fix missing include
2022-05-19 14:50:17 +08:00
ikrijan
ab82e78c3d Update executor.hpp
explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`
2022-05-18 21:15:44 +08:00
silent
a295cd8635 Closes klemens-morgenstern/boost-process#218 2022-05-18 21:15:44 +08:00
silent
b8bcfa2e11 fix missing headers 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
ed659bf129 Removed overly constraint tests. 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
4cadf1d333 Multiple windows test fixes 2022-05-18 21:15:44 +08:00
Klemens
220bec28bf Increased log level on windows. 2022-05-18 21:15:44 +08:00
Klemens
ee3c2cfeeb Trying to catch windows early complete. 2022-05-18 21:15:44 +08:00
Klemens
221550a848 Added missing work guard on windows. 2022-05-18 21:15:44 +08:00
Klemens
b7821ccf09 Closes boostorg/process#191. 2022-05-18 21:15:44 +08:00
Klemens
1f464b3eb5 Closes boostorg/process#189. 2022-05-18 21:15:44 +08:00
Klemens
5abb4f4a23 Multiple fixes. 2022-05-18 21:15:44 +08:00
Klemens
722bd31cdb Changed child(pid_t) signature. 2022-05-18 21:15:44 +08:00
Klemens
e358dc52a2 Closes boostorg/process#197. 2022-05-18 21:15:44 +08:00
Klemens
d54788a385 Attempting to fix wchar_t build error on circle. 2022-05-18 21:15:44 +08:00
Klemens
4a5d711c86 Closes boostorg/process#121 2022-05-18 21:15:44 +08:00
Klemens
d11e327ab0 Closes boostorg/process#190 2022-05-18 21:15:44 +08:00
Klemens
edaf70a7a7 Removed unneeded WNOHANG. 2022-05-18 21:15:44 +08:00
Klemens Morgenstern
dc8ba65c77 Merge pull request #249 from ikrijan/patch-1
Update executor.hpp
2022-05-13 23:49:56 +08:00
ikrijan
ea26c7b2bd Update executor.hpp
explicit cast to int to silence this: `error: non-constant-expression cannot be narrowed from type 'unsigned long' to 'int' in initializer list [-Wc++11-narrowing]`
2022-05-13 16:50:25 +02:00
hgkjshegfskef
4d1c438d91 Fix missing include 2022-04-20 17:36:20 +02:00
Klemens Morgenstern
d231979a6c Merge pull request #233 from alandefreitas/boost_rel_paths
Adjust documentation relative paths
2021-12-31 21:50:06 +08:00
alandefreitas
a3e8600e40 Adjust docs @boost relative paths 2021-12-28 19:41:40 -03:00
Klemens Morgenstern
f7053f31ec Merge pull request #194 from Shauren/fix-linux-file-descriptor-move
Fix posix implementation of move constructor/assignment in file_descriptor
2021-10-14 14:20:18 +08:00
Shauren
b526ac7ce5 Fix posix implementation of move constructor/assignment in file_descriptor 2021-01-16 17:02:41 +01:00
183 changed files with 16084 additions and 339 deletions

38
.drone.star Normal file
View File

@@ -0,0 +1,38 @@
# Use, modification, and distribution are
# subject to the Boost Software License, Version 1.0. (See accompanying
# file LICENSE.txt)
#
# Copyright Rene Rivera 2020.
# For Drone CI we use the Starlark scripting language to reduce duplication.
# As the yaml syntax for Drone CI is rather limited.
#
#
globalenv={'B2_CI_VERSION': '1', 'B2_VARIANT': 'release'}
linuxglobalimage="cppalliance/droneubuntu1804:1"
windowsglobalimage="cppalliance/dronevs2019"
def main(ctx):
return [
freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),
#linux_cxx("gcc 11 arm64", "g++-11", packages="g++-11", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu2004:multiarch", environment={ 'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '17ba079169m'}, arch="arm64", globalenv=globalenv),
linux_cxx("GCC 10, Debug + Coverage", "g++-10", packages="g++-10 libssl-dev libffi-dev binutils-gold gdb",
image="cppalliance/droneubuntu2004:1", buildtype="boost", buildscript="drone", environment={"GCOV": "gcov-10", "LCOV_VERSION": "1.15", "VARIANT": "process_coverage", "TOOLSET": "gcc", "COMPILER": "g++-10", "CXXSTD": "11", "DRONE_BEFORE_INSTALL" : "process_coverage", "CODECOV_TOKEN": {"from_secret": "codecov_token"}}, globalenv=globalenv, privileged=True),
# A set of jobs based on the earlier .travis.yml configuration:
linux_cxx("Default clang++ with libc++", "clang++-libc++", packages="libc++-dev", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "B2_TOOLSET": "clang-7", "B2_CXXSTD": "11", "VARIANT": "debug", "TOOLSET": "clang", "COMPILER": "clang++-libc++", "CXXSTD": "11", "CXX_FLAGS": "<cxxflags>-stdlib=libc++ <linkflags>-stdlib=libc++", "TRAVISCLANG" : "yes" }, globalenv=globalenv),
linux_cxx("Default g++", "g++", image="cppalliance/droneubuntu1604:1", buildtype="buildtype", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv),
linux_cxx("Clang 3.8, UBasan", "clang++-3.8", packages="clang-3.8 libssl-dev", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
linux_cxx("coverity", "g++", packages="", buildtype="coverity", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'Coverity Scan', 'B2_TOOLSET': 'clang', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.1", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.3", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
]
# from https://github.com/boostorg/boost-ci
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")

34
.drone/drone.bat Executable file
View File

@@ -0,0 +1,34 @@
@ECHO ON
setlocal enabledelayedexpansion
if "%DRONE_JOB_BUILDTYPE%" == "boost" (
echo '==================================> INSTALL'
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
cp -prf boost-ci-cloned/ci .
rm -rf boost-ci-cloned
REM source ci/travis/install.sh
REM The contents of install.sh below:
for /F %%i in ("%DRONE_REPO%") do @set SELF=%%~nxi
SET BOOST_CI_TARGET_BRANCH=%DRONE_COMMIT_BRANCH%
SET BOOST_CI_SRC_FOLDER=%cd%
call ci\common_install.bat
echo '==================================> COMPILE'
REM set B2_TARGETS=libs/!SELF!/test libs/!SELF!/example
set B2_TARGETS=libs/!SELF!/test
cd !BOOST_ROOT!
call bootstrap.bat
b2 headers
b2 --debug-configuration variant=%VARIANT% cxxstd=%CXXSTD% define=%DEFINE% address-model=%ADDRESS_MODEL% toolset=%TOOLSET% --verbose-test libs/!SELF!/test libs/!SELF!/example -j3
) else if "%DRONE_JOB_BUILDTYPE%" == "standalone-windows" (
REM not used
)

199
.drone/drone.sh Executable file
View File

@@ -0,0 +1,199 @@
#!/bin/bash
# Copyright 2020 Rene Rivera, Sam Darwin
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt)
set -xe
export TRAVIS_BUILD_DIR=$(pwd)
export DRONE_BUILD_DIR=$(pwd)
export TRAVIS_BRANCH=$DRONE_BRANCH
export TRAVIS_EVENT_TYPE=$DRONE_BUILD_EVENT
export VCS_COMMIT_ID=$DRONE_COMMIT
export GIT_COMMIT=$DRONE_COMMIT
export REPO_NAME=$DRONE_REPO
export USER=$(whoami)
export CC=${CC:-gcc}
export PATH=~/.local/bin:/usr/local/bin:$PATH
common_install () {
git clone https://github.com/boostorg/boost-ci.git boost-ci-cloned --depth 1
cp -prf boost-ci-cloned/ci .
rm -rf boost-ci-cloned
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
unset -f cd
fi
export SELF=`basename $REPO_NAME`
export BOOST_CI_TARGET_BRANCH="$TRAVIS_BRANCH"
export BOOST_CI_SRC_FOLDER=$(pwd)
. ./ci/common_install.sh
}
if [ "$DRONE_JOB_BUILDTYPE" == "boost" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
$BOOST_ROOT/libs/$SELF/ci/travis/build.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "docs" ]; then
echo '==================================> INSTALL'
export SELF=`basename $REPO_NAME`
pwd
cd ..
mkdir -p $HOME/cache && cd $HOME/cache
if [ ! -d doxygen ]; then git clone -b 'Release_1_8_15' --depth 1 https://github.com/doxygen/doxygen.git && echo "not-cached" ; else echo "cached" ; fi
cd doxygen
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release
cd build
sudo make install
cd ../..
if [ ! -f saxonhe.zip ]; then wget -O saxonhe.zip https://sourceforge.net/projects/saxon/files/Saxon-HE/9.9/SaxonHE9-9-1-4J.zip/download && echo "not-cached" ; else echo "cached" ; fi
unzip -o saxonhe.zip
sudo rm /usr/share/java/Saxon-HE.jar
sudo cp saxon9he.jar /usr/share/java/Saxon-HE.jar
cd ..
BOOST_BRANCH=develop && [ "$TRAVIS_BRANCH" == "master" ] && BOOST_BRANCH=master || true
git clone -b $BOOST_BRANCH https://github.com/boostorg/boost.git boost-root --depth 1
cd boost-root
export BOOST_ROOT=$(pwd)
git submodule update --init libs/context
git submodule update --init tools/boostbook
git submodule update --init tools/boostdep
git submodule update --init tools/docca
git submodule update --init tools/quickbook
rsync -av $TRAVIS_BUILD_DIR/ libs/$SELF
python tools/boostdep/depinst/depinst.py ../tools/quickbook
./bootstrap.sh
./b2 headers
echo '==================================> SCRIPT'
echo "using doxygen ; using boostbook ; using saxonhe ;" > tools/build/src/user-config.jam
./b2 -j3 libs/$SELF/doc//boostrelease
elif [ "$DRONE_JOB_BUILDTYPE" == "codecov" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
cd $BOOST_ROOT/libs/$SELF
ci/travis/codecov.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "valgrind" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
cd $BOOST_ROOT/libs/$SELF
ci/travis/valgrind.sh
elif [ "$DRONE_JOB_BUILDTYPE" == "standalone" ]; then
echo '==================================> INSTALL'
# Installing cmake with apt-get, so not required here:
# pip install --user cmake
echo '==================================> SCRIPT'
export CXXFLAGS="-Wall -Wextra -Werror -std=c++17"
mkdir __build_17
cd __build_17
cmake -DBOOST_JSON_STANDALONE=1 ..
cmake --build .
ctest -V .
export CXXFLAGS="-Wall -Wextra -Werror -std=c++2a"
mkdir ../__build_2a
cd ../__build_2a
cmake -DBOOST_JSON_STANDALONE=1 ..
cmake --build .
ctest -V .
elif [ "$DRONE_JOB_BUILDTYPE" == "coverity" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> SCRIPT'
if [ $VARIANT = "process_valgrind" ];
then export USE_VALGRIND="testing.launcher=valgrind valgrind=on";
fi ;
if [ -n "${COVERITY_SCAN_NOTIFICATION_EMAIL}" -a \( "$TRAVIS_BRANCH" = "develop" -o "$TRAVIS_BRANCH" = "master" \) -a \( "$DRONE_BUILD_EVENT" = "push" -o "$DRONE_BUILD_EVENT" = "cron" \) ] ; then
cd $BOOST_ROOT/libs/$SELF
ci/travis/coverity.sh
fi
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake-superproject" ]; then
echo '==================================> INSTALL'
common_install
echo '==================================> COMPILE'
export CXXFLAGS="-Wall -Wextra -Werror"
mkdir __build_static
cd __build_static
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
-DBOOST_INCLUDE_LIBRARIES=$SELF ..
cmake --build .
ctest --output-on-failure -R boost_$SELF
cd ..
mkdir __build_shared
cd __build_shared
cmake -DBOOST_ENABLE_CMAKE=1 -DBUILD_TESTING=ON -DBoost_VERBOSE=1 \
-DBOOST_INCLUDE_LIBRARIES=$SELF -DBUILD_SHARED_LIBS=ON ..
cmake --build .
ctest --output-on-failure -R boost_$SELF
elif [ "$DRONE_JOB_BUILDTYPE" == "cmake1" ]; then
echo '==================================> INSTALL'
pip install --user cmake
echo '==================================> SCRIPT'
export SELF=`basename $REPO_NAME`
BOOST_BRANCH=develop && [ "$DRONE_BRANCH" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
mkdir -p libs/$SELF
cp -r $DRONE_BUILD_DIR/* libs/$SELF
# git submodule update --init tools/boostdep
git submodule update --init --recursive
cd libs/$SELF
../../../b2 -sBOOST_BUILD_PATH=.
../../../b2 $MULTITHREAD with-valgrind address-model=64 architecture=x86 $USE_VALGRIND toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
../../../b2 $MULTITHREAD without-valgrind address-model=64 architecture=x86 toolset=$TOOLSET cxxflags="--coverage -DBOOST_TRAVISCI_BUILD -std=$CXX_STANDARD" linkflags="--coverage" -sBOOST_BUILD_PATH=. $REPORT_CI
fi

201
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,201 @@
name: CI
on:
pull_request:
push:
branches:
- master
- develop
- feature/**
env:
UBSAN_OPTIONS: print_stacktrace=1
jobs:
posix:
strategy:
fail-fast: false
matrix:
include:
- toolset: gcc-5
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: g++-5
- toolset: gcc-6
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: g++-6
- toolset: gcc-7
cxxstd: "11,14,17"
os: ubuntu-18.04
- toolset: gcc-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: g++-10
- toolset: gcc-12
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: clang
compiler: clang++-3.9
cxxstd: "11,14"
os: ubuntu-18.04
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "11,14"
os: ubuntu-18.04
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "11,14,1z"
os: ubuntu-18.04
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "11,14,17"
os: ubuntu-18.04
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "11,14,17"
os: ubuntu-18.04
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "11,14,17"
os: ubuntu-20.04
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "11,14,17,2a"
os: ubuntu-20.04
install: clang-12
- toolset: clang
compiler: clang++-13
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "11,14,17,20,2b"
os: ubuntu-22.04
install: clang-14
- toolset: clang
cxxstd: "11,14,17,2a"
os: macos-11
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
./bootstrap.sh
./b2 -d0 headers
- name: Create user-config.jam
if: matrix.compiler
run: |
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
- name: Run tests
run: |
cd ../boost-root
./b2 -j3 libs/$LIBRARY/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} variant=debug,release
windows:
strategy:
fail-fast: false
matrix:
include:
- toolset: msvc-14.0
cxxstd: "14,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "11,14,17,2a"
addrmd: 64
os: windows-2019
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
- name: Run tests
shell: cmd
run: |
cd ../boost-root
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker

1
.gitignore vendored
View File

@@ -31,4 +31,5 @@
/notes.cpp
/notes_p.txt
.settings
.DS_Store

View File

@@ -11,7 +11,6 @@ add_library(boost_process INTERFACE)
add_library(Boost::process ALIAS boost_process)
target_include_directories(boost_process INTERFACE include)
target_link_libraries(boost_process
INTERFACE
Boost::algorithm

View File

@@ -1,18 +1,21 @@
# [Boost Process (Boost.Process)](https://github.com/klemens-morgenstern/boost-process)
# [Boost Process (Boost.Process)](https://github.com/boostorg/process)
Boost.process is a library for comfortable management of processes, released with boost 1.64.0.
### Test results
Branches | Linux | OSX | Windows | Code coverage | Matrix |
----------------|-------|-----|---------| ------------- |--------|
Develop: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=develop&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/develop?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/develop) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=develop&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=develop&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=develop)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=develop) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html)
Master: | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=linux)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=linux)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=linux) | [![Build Status](https://travis-ci.org/klemens-morgenstern/boost-process.svg?branch=master&env=BADGE=osx)](https://travis-ci.org/klemens-morgenstern/boost-process) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=osx)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=osx) | [![Build status](https://ci.appveyor.com/api/projects/status/peup7e6m0e1bb5ba/branch/master?svg=true)](https://ci.appveyor.com/project/klemens-morgenstern/boost-process/branch/master) [![badge](https://api.report.ci/status/klemens-morgenstern/boost-process/badge.svg?branch=master&build=windows)](https://api.report.ci/status/klemens-morgenstern/boost-process?branch=master&build=windows) | [![Coverage Status](https://coveralls.io/repos/github/klemens-morgenstern/boost-process/badge.svg?branch=master)](https://coveralls.io/github/klemens-morgenstern/boost-process?branch=master) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html)
| Branches | Linux / Windows | Code coverage | Matrix |
|----------|----------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| Develop: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/develop/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-develop-lightgray.svg)](http://www.boost.org/development/tests/develop/developer/process.html) |
| Master: | [![Build Status](https://drone.cpp.al/api/badges/boostorg/process/status.svg?ref=refs/heads/develop)](https://drone.cpp.al/boostorg/process) | [![codecov](https://codecov.io/gh/boostorg/process/branch/master/graph/badge.svg?token=AhunMqTSpA)](https://codecov.io/gh/boostorg/process) | [![Matrix](https://img.shields.io/badge/matrix-master-lightgray.svg)](http://www.boost.org/development/tests/master/developer/process.html) |
[Open Issues](https://github.com/klemens-morgenstern/boost-process/issues)
[Latest developer documentation](http://klemens-morgenstern.github.io/process/)
[Open Issues](https://github.com/boostorg/process/issues)
[Latest developer documentation](https://www.boost.org/doc/libs/develop/doc/html/process.html)
### About
This C++11 library is the current result of a long attempt to get a boost.process library, which is going on since 2006.

View File

@@ -24,12 +24,13 @@ generators.register-standard common.copy : XML : XMLPROCESSWORKAROUND ;
xmlprocessworkaround posix_pseudocode : posix_pseudocode.xml ;
xmlprocessworkaround windows_pseudocode : windows_pseudocode.xml ;
path-constant INCLUDES : ../../.. ;
doxygen autodoc
:
../../../boost/process.hpp
[ glob ../../../boost/process/*.hpp ]
:
$(INCLUDES)/boost/process.hpp
[ glob $(INCLUDES)/boost/process/*.hpp ]
:
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
<doxygen:param>PREDEFINED=BOOST_PROCESS_DOXYGEN
<doxygen:param>HIDE_UNDOC_CLASSES=YES
@@ -42,11 +43,49 @@ doxygen autodoc
doxygen reference_v2
:
$(INCLUDES)/boost/process/v2.hpp
[ glob $(INCLUDES)/boost/process/v2/*.hpp ]
:
<doxygen:param>EXCLUDE_SYMBOLS=BOOST_ASIO_INITFN_RESULT_TYPE
<doxygen:param>PROJECT_NAME="Process V2"
<doxygen:param>PROJECT_BRIEF="The process library"
<doxygen:param>MACRO_EXPANSION=YES
<doxygen:param>EXPAND_ONLY_PREDEF=YES
<doxygen:param>"PREDEFINED=\\
GENERATING_DOCUMENTATION=1 \\
BOOST_PROCESS_V2_ASIO_NAMESPACE=boost::asio \\
\"BOOST_PROCESS_V2_BEGIN_NAMESPACE=namespace boost { namespace process { namespace v2 { \" \\
\"BOOST_PROCESS_V2_END_NAMESPACE= } } }\" \\
BOOST_PROCESS_V2_NAMESPACE=boost::process::v2 \\
BOOST_PROCESS_V2_DECL \\
BOOST_PROCESS_V2_SOURCE \\
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(x,y)=deduced \\
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(X)=Token \\
BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(E)=DEFAULT_TYPE \\
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN=DEFAULT \\
BOOST_CONSTEXPR=constexpr \\
BOOST_CXX14_CONSTEXPR=constexpr \\
BOOST_ATTRIBUTE_NODISCARD=[[nodiscard]]
"
<doxygen.doxproc.id>reference_v2
<doxygen:param>SHOW_USED_FILES=NO
<doxygen:param>SHOW_FILES=NO
<doxygen:param>SHOW_NAMESPACES=YES
<doxygen:param>CLASS_DIAGRAMS=NO
<doxygen:param>SORT_MEMBERS_CTORS_1ST=YES
<doxygen:param>HIDE_UNDOC_CLASSES=NO
<xsl:path>.
;
boostbook standalone
:
process.qbk
:
<dependency>autodoc
<dependency>reference_v2
<dependency>images
<dependency>images_glob
<xsl:param>boost.root=../../../..

View File

@@ -8,4 +8,6 @@ A special thank you goes to [@http://www.intra2net.com/ Intra2net AG] (especiall
Great thanks also goes to Boris Schaeling, who despite having boost.process rejected, went on to work on it and maintained it up until this day and participated in the development of the current version.
Many Thanks, to [@https://github.com/time-killer-games Samuel Venable] for contributing the v2::ext functionality and all the research that went into it.
[endsect]

View File

@@ -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]

View File

@@ -83,7 +83,7 @@ will be called on the respective events on process launching. The names are:
As an example:
```
child c("ls", on_setup([](){cout << "On Setup" << endl;});
child c("ls", on_setup([](){cout << "On Setup" << endl;}));
```

View File

@@ -31,7 +31,7 @@ else if (pid == 0) //child process
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_exec_error">on_exec_error</methodname>(*this);
<emphasis>unspecified();</emphasis>//here the error is send to the father process interally
<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::child">child</classname>(); //for C++ compliance
@@ -39,7 +39,7 @@ else if (pid == 0) //child process
<classname alt="boost::process::child">child</classname> c(pid, exit_code);
<emphasis>unspecified();</emphasis>//here, we read the the error from the child process
<emphasis>unspecified();</emphasis>//here, we read the error from the child process
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
for (auto &amp; s : seq)
@@ -48,7 +48,7 @@ else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because a on_success handler might've errored.
//now we check again, because an on_success handler might've errored.
if (<methodname alt="boost::process::extend::posix_executor::error">error</methodname>())
{
for (auto &amp; s : seq)

View File

@@ -11,6 +11,8 @@
]
]
[note [link process.v2 Process V2] is available as experimental]
[include introduction.qbk]
[include concepts.qbk]
[include tutorial.qbk]
@@ -19,3 +21,4 @@
[include faq.qbk]
[xinclude autodoc.xml]
[include acknowledgements.qbk]
[include v2.qbk]

View File

@@ -82,10 +82,10 @@ int result = bp::system("/usr/bin/g++", "main.cpp");
```
With that syntax we still have "g++" hard-coded, so let's assume we get the string
from an external source as `boost::filesystem::path`, we can do this too.
from an external source as `boost::process::filesystem::path`, we can do this too.
```
boost::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
boost::process::filesystem::path p = "/usr/bin/g++"; //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
@@ -93,7 +93,7 @@ Now we might want to find the `g++` executable in the `PATH`-variable, as the `c
`Boost.process` provides a function to this end: bp::search_path.
```
boost::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
boost::process::filesystem::path p = bp::search_path("g++"); //or get it from somewhere else.
int result = bp::system(p, "main.cpp");
```
@@ -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,7 +357,7 @@ 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

11
doc/v2.qbk Normal file
View File

@@ -0,0 +1,11 @@
[section:v2 Process V2]
[include v2/introduction.qbk]
[include v2/quickstart.qbk]
[include v2/launcher.qbk]
[include v2/start_dir.qbk]
[include v2/stdio.qbk]
[include v2/env.qbk]
[xinclude reference_v2.xml]
[endsect]

48
doc/v2/env.qbk Normal file
View File

@@ -0,0 +1,48 @@
[section:env Environment]
The `environment` namespace provides all sorts of facilities to query and manipulate the environment of the current process.
The api should be straight forward, but one oddity that needs to be pointed out is, that environment names
are not case sensitive on windows. The key_traits class implements the proper traits depending on the current system.
Additionally, environment can be lists separated by `:` or `;`; `environment::value` and
`environment::value_view` can be used to iterate those.
Beyond that, the requirements on an environment are a low as possible;
an environment is either a list of strings or a list of string-pairs. It is however recommended to use the environment types,
as to have the right value comparisons.
To note is the `find_executable` functions, which searches in an environment for an executable.
```
// search in the current environment
auto exe = environment::find_executable("g++");
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto other_exe = environment::find_executable("g++", my_env);
```
[section:process_env Subprocess environment]
The subprocess environment assignment follows the same constraints:
```
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"},
{"PATH", {"/bin", "/usr/bin"}}
};
auto exe = find_executable("g++");
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```
[endsect]
[endsect]

94
doc/v2/introduction.qbk Normal file
View File

@@ -0,0 +1,94 @@
[section:introduction Introduction]
Boost.process V2 is an redesign of boost.process, based on previous
design mistakes & improved system APIs.
The major changes are
* Simplified interface
* Reliance on pidfd_open on linux
* Full asio integration
* Removed unreliable functionality
* UTF8 Support
* separate compilation
* fd safe by default
[section:simplified Simplified Interface]
In process v1 one can define partial settings in the constructor of the process,
which has lead to a small DSL.
child c{exe="test", args+="--help", std_in < null(), env["FOO"] += "BAR"};
While this looks fancy at first, it really does not scale well with more parameters.
For process v2, the interfaces is simple:
extern std::unordered_map<std::string, std::string> my_env;
extern asio::io_context ctx;
process proc(ctx, "./test", {"--help"}, process_io{nullptr, {}, {}}, process_environment(my_env));
Every initializer addresses one logical component (e.g. stdio) instead of multiple ones accumulating.
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
exe-args that can be randomly spread out.
[endsect]
[section:pidfd_open pidfd_open]
Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a
file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
FreeBSD has a similar feature with `pdfork` which is also supported, while windows has provided `HANDLE`s
for processes all along.
Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting
for processes.
[endsect]
[section:asio Full asio integration]
Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging
for deadlocks.
Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and
file-handles for the subprocess.
[endsect]
[section:unreliable Unreliable functionality]
Certain parts of boost.process were not as reliable as they should've been.
This concerns especially the `wait_for` and `wait_until` functions on the process.
The latter are easy to do on windows, but posix does not provide an API for this.
Thus the wait_for used signals or fork, which was all but safe.
Since process v2 is based on asio and thus supports cancellation,
a wait_for can not safely be implemented with an async_wait + timeout.
[endsect]
[section:utf8 UTF-8]
["UTF-8 or GTFO]--Vinnie Falco
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere.
[endsect]
[section:src Separate compilation]
Boost.process v2 supports separate compilation similar to other boost libraries.
It can be achieved by defining `BOOST_PROCESS_V2_SEPARATE_COMPILATION` and including
`<process/v2/src.hpp>` in a single compile unit.
[endsect]
[section:limit_fd Fd safe by default]
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
posix systems create a problem with inheriting file handles by default.
Process V2 will automatically close all non-whitelisted descriptors,
without needing any option to enable it.
[endsect]
[endsect]

128
doc/v2/launcher.qbk Normal file
View File

@@ -0,0 +1,128 @@
[section:launchers Launcher]
The process creation is done by a process_launcher.
The constructor of `process` will use the default_launcher, which varies by system.
There are additional launcher available on most systems.
[table:launchers Launcher overview
[[Name] [Summary] [Default on] [Available on]]
[[`windows::default_launcher`] [Launcher using `CreateProcessW`] [windows] [windows]]
[[`windows::as_user_launcher`] [Launcher using `CreateProcessAsUserW`] [] [windows]]
[[`windows::with_logon_launcher`] [Launcher using `CreateProcessWithLogonW`] [] [windows]]
[[`windows::with_token_launcher`] [Launcher using `CreateProcessWithTokenW`] [] [windows]]
[[`posix::default_launcher`] [Launcher using fork & an error pipe] [most of posix] [posix]]
[[`posix::fork_and_forget`] [Launcher using fork without error pipe] [] [posix]]
[[`posix::pdfork_launcher`] [Launcher using pdfork with an error pipe] [FreeBSD] [FreeBSD]]
[[`posix::vfork_launcher`] [Launcher using vfork] [] [posix]]
]
A launcher is invoked through the call operator.
```
auto l = windows::as_user_launcher((HANDLE)0xDEADBEEF);
asio::io_context ctx;
boost::system::error_code ec;
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
```
The launcher will call certain functions on the initializer if they're present, as documented below.
The initializer are used to modify the process behaviour.
[section:linux Linux Launchers]
The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
This can be prevented by using the `fork_and_forget_launcher`.
Alternatively, the `vfork_launcher` can report errors directly back to the parent process.
Thus some calls to the initializers occur after forking from the child process.
```
struct custom_initializer
{
// functions called from the parent process:
// called before a call to fork. A returned error will cancel the launch.
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occurred during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called after successful process creation
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occurred when forking, in addition to on_error.
template<typename Launcher>
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
template<typename Launcher>
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called after a failed call to execve from the child process.
template<typename Launcher>
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
};
```
The call sequence on success:
'''
<imagedata fileref="boost_process/posix_success.svg"/>
'''
The call sequence when fork fails:
'''
<imagedata fileref="boost_process/posix_fork_err.svg"/>
'''
The call sequence when exec fails:
'''
<imagedata fileref="boost_process/posix_exec_err.svg"/>
'''
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
[endsect]
[section:windows Windows Launchers]
Windows launchers are pretty straight forward, they will call the following functions on the initializer if present.
```
struct custom_initializer
{
// called before a call to CreateProcess. A returned error will cancel the launch.
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
// called for every initializer if an error occurred during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
const error_code & ec);
// called after successful process creation
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
};
```
[note All the additional launchers for windows inherit `default_launcher`]
The call sequence is as follows:
'''
<imagedata fileref="boost_process/windows_exec.svg"/>
'''
[endsect]
[endsect]

123
doc/v2/quickstart.qbk Normal file
View File

@@ -0,0 +1,123 @@
[section:quickstart Quickstart]
A process needs four things to be launched:
* an asio execution_context / executor
* a path to an executable
* a list of arguments
* a variadic set of initializers
```
// process(asio::any_io_executor, filesystem::path, range<string> args, AdditionalInitializers...)
asio::io_context ctx;
process proc(ctx, "/usr/bin/cp", {"source.txt", "target.txt"});
```
The started process can then be awaited or terminated.
[section:lifetime Lifetime]
If the process handle goes out of scope, it will terminate the subprocess.
You can prevent this, by calling `proc.detach()`; do however note that this
can lead to zombie processes.
A process that completed will deliver an exit-code,
which can be obtained by calling `.exit_code` on the exited process and which is
also returned from `.wait()`.
```
process proc("/bin/ls", {});
assert(proc.wait() == 0);
```
The normal exit-code is what the subprocess returned from `main`;
posix will however add additional information about the process.
This is called the `native_exit_code`.
The `.running()` function can be used to detect if the process is still active.
[endsect]
[section:signal Signalling the subprocess]
The parent process can signal the subprocess demanding certain actions.
`.terminate` will cause the subprocess to exit immediately (`SIGKILL` on posix).
This is the only reliable & portable way to end a subprocess.
```
process proc("/bin/totally-not-a-virus", {});
proc.terminate();
```
`.request_exit` will ask the subprocess to shutdown (`SIGTERM` on posix),
which the subprocess might ignore.
```
process proc("/bin/bash", {});
proc.request_exit();
proc.wait();
```
`.interrupt` will send an SIGINT to the subprocess, which a subprocess might
interpret as a signal to shutdown.
[warning interrupt requires the initializer `windows::create_new_process_group` to be set]
```
process proc("/usr/bin/addr2line", {});
proc.request_exit();
proc.wait();
```
[endsect]
[section:execute Execute functions]
Process v2 provides `execute` and `async_execute` functions that can be used for managed executions.
```
assert(execute(process("/bin/ls", {}) == 0));
```
The async version supports cancellation and will forward cancellation types as follows:
- asio::cancellation_type::total -> interrupt
- asio::cancellation_type::partial -> request_exit
- asio::cancellation_type::terminal -> terminate
```
asio::io_context ctx;
asio::steady_timer timeout{ctx, std::chrono::seconds(10)};
asio::cancellation_signal sig;
async_execute(process("/usr/bin/g++", {"hello_world.cpp"}),
asio::bind_cancellation_slot(sig.slot(),
[&](error_code ec, int exit_code)
{
timeout.cancel(); // we're done earlier
}));
timeout.async_wait(
[&](error_code ec)
{
if (ec) // we were cancelled, do nothing
return ;
sig.emit(asio::cancellation_type::partial);
// request exit first, but terminate after another 10 sec
timeout.expires_after(std::chrono::seconds(10));
timeout.async_wait(
[&](error_code ec)
{
if (!ec)
sig.emit(asio::cancellation_type::terminal);
});
});
```
[endsect]
[endsect]

16
doc/v2/start_dir.qbk Normal file
View File

@@ -0,0 +1,16 @@
[section:start_dir process_start_dir]
The easier initializer to use is `process_start_dir`:
```
asio::io_context ctx;
process ls(ctx, "/ls", {}, process_start_dir("/home"));
ls.wait();
```
This will run `ls` in the folder `/home` instead of the current folder.
[warning If your path is relative, it may fail on posix, because the directory is changed before a call to execve.]
[endsect]

89
doc/v2/stdio.qbk Normal file
View File

@@ -0,0 +1,89 @@
[section:stdio stdio]
When using io with a subprocess, all three standard streams (stdin, stdout, stderr) get set for the child-process.
The default setting is to inherit the parent process.
This feature meant to be flexible, which is why there is little checking on the arguments assigned to one of those streams.
[section:pipe Pipe]
asio pipes can be used for io. When using in process_stdio they will get
automatically connected and the other side will get assigned to the child process:
```
asio::io_context ctx;
asio::readable_pipe rp;
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, rp, { /* err to default */ }});
std::string output;
system::error_code ec;
rp.read(asio::dynamic_buffer(output), ec);
assert(ec == asio::eof);
proc.wait();
```
readable pipes can be assigned to `out` an `err`, while writable_pipes can be assigned to `in`.
[endsect]
[section:file `FILE*`]
`FILE*` can also be used for either side; this allows the `stdin`, `stderr`, `stdout` macros to be used:
```
asio::io_context ctx;
// forward both stderr & stdout to stdout of the parent process
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, stdout, stdout});
proc.wait();
```
[endsect]
[section:null `nullptr`]
`nullptr` may be used to set a given stream to be opened on the null-device (`/dev/null` on posix, `NUL` on windows).
This is used to ignore output or give only EOF as input.
```
asio::io_context ctx;
// ignore stderr
process proc(ctx, "/usr/bin/g++", {"--version"}, process_stdio{{ /* in to default */}, {}, nullptr});
proc.wait();
```
[endsect]
[section:native_handle `native_handle`]
A native handle can be used as well, which means an `int` on posix or a `HANDLE` on windows.
Furthermore, any object that has a `native_handle` returning that native handle type is valid, too.
```
asio::io_context ctx;
// ignore stderr
asio::ip::tcp::socket sock{ctx};
connect_my_socket(sock);
process proc(ctx, "~/not-a-virus", {}, process_stdio{sock, sock, nullptr});
proc.wait();
```
[endsect]
[section:popen popen]
Additionally, process v2 provides a `popen` class.
It starts a process and connects pipes for stdin and stdout, so that the popen object can be used as a stream.
```
popen proc(executor, "/usr/bin/addr2line, {argv[0]});
asio::write(proc, asio::buffer("main\n"));
std::string line;
asio::read_until(proc, asio::dynamic_buffer(line), '\n');
```
[endsect]
[endsect]

View File

@@ -29,7 +29,7 @@ else
for (auto &amp; s : seq)
s.<methodname alt="boost::process::extend::handler::on_error">on_success</methodname>(*this);
//now we check again, because a on_success handler might've errored.
//now we check again, because an on_success handler might've errored.
if (<methodname alt="boost::process::extend::windows_executor::error">error</methodname>())
{
for (auto &amp; s : seq)

View File

@@ -22,7 +22,7 @@ int main()
bp::std_in < bp::null //null in
);
boost::filesystem::path p = "input.txt";
boost::process::filesystem::path p = "input.txt";
bp::system(
"test.exe",

View File

@@ -8,7 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process.hpp>
#include <boost/filesystem.hpp>
#include <boost/process/filesystem.hpp>
namespace bp = boost::process;
@@ -19,9 +19,9 @@ int main()
bp::start_dir="../foo"
);
boost::filesystem::path exe = "test.exe";
boost::process::filesystem::path exe = "test.exe";
bp::system(
boost::filesystem::absolute(exe),
boost::process::filesystem::absolute(exe),
bp::start_dir="../foo"
);
}

17
example/v2/Jamfile.jam Normal file
View File

@@ -0,0 +1,17 @@
# Copyright (c) 2022 Klemens Morgenstern
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
project : requirements
<include>../../..
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
;
import testing ;
alias filesystem : /boost//filesystem : <link>static ;
exe intro : intro.cpp filesystem ;
exe intro_popen : intro_popen.cpp filesystem ;

39
example/v2/intro.cpp Normal file
View File

@@ -0,0 +1,39 @@
// Copyright (c) 2022 Klemens Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//[intro
#include <boost/process/v2.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <iostream>
namespace proc = boost::process::v2;
namespace asio = boost::asio;
int main()
{
asio::io_context ctx;
asio::readable_pipe p{ctx};
const auto exe = proc::environment::find_executable("gcc");
proc::process c{ctx, exe, {"--version"}, proc::process_stdio{nullptr, p}};
std::string line;
boost::system::error_code ec;
auto sz = asio::read(p, asio::dynamic_buffer(line), ec);
assert(ec == asio::error::eof);
std::cout << "Gcc version: '" << line << "'" << std::endl;
c.wait();
}
//]

View File

@@ -0,0 +1,36 @@
// Copyright (c) 2022Klemens Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//[intro
#include <boost/process/v2.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <iostream>
namespace proc = boost::process::v2;
namespace asio = boost::asio;
int main()
{
asio::io_context ctx;
const auto exe = proc::environment::find_executable("gcc");
proc::popen c{ctx, exe, {"--version"}};
std::string line;
boost::system::error_code ec;
auto sz = asio::read(c, asio::dynamic_buffer(line), ec);
assert(ec == asio::error::eof);
std::cout << "Gcc version: '" << line << "'" << std::endl;
c.wait();
}
//]

View File

@@ -8,6 +8,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/process.hpp>
#include <boost/process/extend.hpp>
#include <boost/process/windows.hpp>
#include <iostream>
@@ -22,9 +23,9 @@ int main()
bp::system("test.exe",
bp::on_setup([](auto &e)
bp::extend::on_setup([](auto &e)
{ e.startup_info.dwFlags = STARTF_RUNFULLSCREEN; }),
bp::on_error([](auto&, const std::error_code & ec)
bp::extend::on_error([](auto&, const std::error_code & ec)
{ std::cerr << ec.message() << std::endl; })
);
}

View File

@@ -5,7 +5,7 @@
/** \file boost/process/async.hpp
The header which provides the basic asynchrounous features.
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.

View File

@@ -26,7 +26,7 @@ namespace boost { namespace process {
#if defined(BOOST_PROCESS_DOXYGEN)
/** Class implementing and asnychronous I/O-Object for use with boost.asio.
/** Class implementing an asnychronous I/O-Object for use with boost.asio.
* It is based on the corresponding I/O Object, that is either boost::asio::windows::stream_handle or
* boost::asio::posix::stream_descriptor.
*

View File

@@ -11,7 +11,7 @@
/**
* \file boost/process/async_system.hpp
*
* Defines the asynchrounous version of the system function.
* Defines the asynchronous version of the system function.
*/
#ifndef BOOST_PROCESS_ASYNC_SYSTEM_HPP
@@ -38,12 +38,11 @@ namespace process {
namespace detail
{
template<typename ExitHandler>
template<typename Handler>
struct async_system_handler : ::boost::process::detail::api::async_handler
{
boost::asio::io_context & ios;
boost::asio::async_completion<
ExitHandler, void(boost::system::error_code, int)> init;
Handler handler;
#if defined(BOOST_POSIX_API)
bool errored = false;
@@ -52,9 +51,8 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
template<typename ExitHandler_>
async_system_handler(
boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler)
ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
{
}
@@ -64,21 +62,15 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API)
errored = true;
#endif
auto & h = init.completion_handler;
auto h = std::make_shared<Handler>(std::move(handler));
boost::asio::post(
ios.get_executor(),
[h, ec]() mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
});
}
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
get_result()
{
return init.result.get();
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{
@@ -86,10 +78,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
if (errored)
return [](int , const std::error_code &){};
#endif
auto & h = init.completion_handler;
auto h = std::make_shared<Handler>(std::move(handler));
return [h](int exit_code, const std::error_code & ec) mutable
{
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
(*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
};
}
};
@@ -120,21 +112,36 @@ inline boost::process::detail::dummy
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif
namespace detail
{
struct async_system_init_op
{
template<typename Handler, typename ... Args>
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
{
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
child(ios, std::forward<Args>(args)..., async_h ).detach();
}
};
}
template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
{
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
has_err_handling;
static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
child(ios, std::forward<Args>(args)..., async_h ).detach();
return async_h.get_result();
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
);
}

View File

@@ -168,7 +168,7 @@ struct exe_builder
string_type exe;
std::vector<string_type> args;
void operator()(const boost::filesystem::path & data)
void operator()(const boost::process::filesystem::path & data)
{
not_cmd = true;
if (exe.empty())

View File

@@ -125,7 +125,10 @@ public:
boost::process::detail::throw_error(ec, "wait error");
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
std::error_code ec;
@@ -135,6 +138,7 @@ public:
}
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
std::error_code ec;
@@ -142,6 +146,7 @@ public:
boost::process::detail::throw_error(ec, "wait_until error");
return b;
}
#endif
bool running(std::error_code & ec) noexcept
{
@@ -178,13 +183,16 @@ public:
}
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
}
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
{
if (!_exited())
@@ -197,7 +205,7 @@ public:
}
return true;
}
#endif
bool valid() const
{

View File

@@ -21,7 +21,9 @@
#include <system_error>
#include <boost/system/api_config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/process/exception.hpp>
#include <boost/assert/source_location.hpp>
#if defined(BOOST_POSIX_API)
#include <errno.h>
@@ -71,31 +73,33 @@ inline std::error_code get_last_error() noexcept
}
#endif
inline void throw_last_error(const std::string & msg)
inline void throw_last_error(const std::string & msg, boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error(), msg);
boost::throw_exception(process_error(get_last_error(), msg), loc);
}
inline void throw_last_error(const char * msg)
inline void throw_last_error(const char * msg, boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error(), msg);
boost::throw_exception(process_error(get_last_error(), msg), loc);
}
inline void throw_last_error()
inline void throw_last_error(boost::source_location const & loc = boost::source_location())
{
throw process_error(get_last_error());
boost::throw_exception(process_error(get_last_error()), loc);
}
inline void throw_error(const std::error_code& ec)
inline void throw_error(const std::error_code& ec,
boost::source_location const & loc = boost::source_location())
{
if (ec)
throw process_error(ec);
boost::throw_exception(process_error(ec), loc);
}
inline void throw_error(const std::error_code& ec, const char* msg)
inline void throw_error(const std::error_code& ec, const char* msg,
boost::source_location const & loc = boost::source_location())
{
if (ec)
throw process_error(ec, msg);
boost::throw_exception(process_error(ec, msg), loc);
}
template<typename Char> constexpr Char null_char();
@@ -114,6 +118,8 @@ template<typename Char> constexpr Char space_sign();
template<> constexpr char space_sign<char> () {return ' '; }
template<> constexpr wchar_t space_sign<wchar_t> () {return L' '; }
}
}
}
}}}
#endif

View File

@@ -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,

View File

@@ -39,10 +39,10 @@ inline std::string build_cmd_shell(const std::string & exe, std::vector<std::str
//the first one is put directly onto the output,
//because then I don't have to copy the whole string
arg.insert(arg.begin(), '"' );
arg += '"'; //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;
@@ -112,7 +112,10 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
{
if (exe.empty()) //cmd style
{
exec.exe = args.front().c_str();
if (args.empty())
exec.exe = "";
else
exec.exe = args.front().c_str();
exec.cmd_style = true;
}
else
@@ -139,7 +142,7 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
}
static exe_cmd_init cmd_shell(std::string&& cmd)
{
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
std::vector<std::string> args = {"-c", cmd};
std::string sh = shell().string();
return exe_cmd_init(
@@ -155,13 +158,15 @@ private:
std::vector<char*> exe_cmd_init<char>::make_cmd()
{
// any string must be writable.
static char empty_string[1] = "";
std::vector<char*> vec;
if (!exe.empty())
vec.push_back(&exe.front());
vec.push_back(exe.empty() ? empty_string : &exe.front());
if (!args.empty()) {
for (auto & v : args)
vec.push_back(&v.front());
vec.push_back(v.empty() ? empty_string : &v.front());
}
vec.push_back(nullptr);

View File

@@ -11,7 +11,7 @@
#define BOOST_PROCESS_POSIX_PIPE_HPP
#include <boost/filesystem.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/process/detail/posix/compare_handles.hpp>
#include <system_error>
#include <array>
@@ -77,12 +77,9 @@ 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
@@ -90,11 +87,11 @@ public:
if (err != EINTR)
::boost::process::detail::throw_last_error();
}
return write_len;
return static_cast<int_type>(write_len);
}
int_type read(char_type * data, int_type count)
{
int_type read_len;
ssize_t read_len;
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
{
//Try again if interrupted
@@ -102,7 +99,7 @@ public:
if (err != EINTR)
::boost::process::detail::throw_last_error();
}
return read_len;
return static_cast<int_type>(read_len);
}
bool is_open() const

View File

@@ -26,6 +26,8 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
template<typename Executor>
@@ -149,14 +151,15 @@ class executor
int _pipe_sink = -1;
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
const auto len = std::strlen(msg);
const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), len + 1};
::write(_pipe_sink, &data[0], sizeof(int) * 2);
::write(_pipe_sink, msg, len);
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::write(_pipe_sink, msg, len));
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
@@ -259,7 +262,10 @@ class executor
return;
//EAGAIN not yet forked, EINTR interrupted, i.e. try again
else if ((err != EAGAIN ) && (err != EINTR))
set_error(std::error_code(err, std::system_category()), "Error read pipe");
{
set_error(std::error_code(err, std::system_category()), "Error read pipe");
return;
}
}
set_error(ec, std::move(msg));
}
@@ -321,10 +327,20 @@ public:
void set_error(const std::error_code &ec, const char* msg)
{
if (pid != 0 && pid != -1) // reap-zombie
::waitpid(pid, nullptr, 0);
internal_error_handle(ec, msg, has_error_handler(), has_ignore_error(), shall_use_vfork());
}
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
std::vector<int> get_used_handles() const
{
if (_pipe_sink == -1)
return {};
else
return {_pipe_sink};
};
};
template<typename Sequence>
@@ -434,6 +450,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
if (_ec)
{
//if an error occurred we need to reap the child process
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
@@ -527,6 +544,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
if (_ec)
{
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}

View File

@@ -8,7 +8,8 @@
#include <fcntl.h>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/core/exchange.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -23,7 +24,7 @@ struct file_descriptor
file_descriptor() = default;
explicit file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
explicit file_descriptor(const boost::process::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}
@@ -39,10 +40,22 @@ struct file_descriptor
}
file_descriptor(const file_descriptor & ) = delete;
file_descriptor(file_descriptor && ) = default;
file_descriptor(file_descriptor &&other)
: _handle(boost::exchange(other._handle, -1))
{
}
file_descriptor& operator=(const file_descriptor & ) = delete;
file_descriptor& operator=(file_descriptor && ) = default;
file_descriptor& operator=(file_descriptor &&other)
{
if (this != &other)
{
if (_handle != -1)
::close(_handle);
_handle = boost::exchange(other._handle, -1);
}
return *this;
}
~file_descriptor()
{

View File

@@ -11,6 +11,8 @@
#include <dirent.h>
#include <sys/stat.h>
#include <algorithm>
#include <memory>
#include <cstdlib>
#include <boost/process/detail/posix/handler.hpp>
namespace boost { namespace process { namespace detail { namespace posix {

View File

@@ -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

View File

@@ -34,7 +34,7 @@ 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.
if (errno != ECHILD) //because it no child is running, then this one isn't either, obviously.
ec = ::boost::process::detail::get_last_error();
return false;
}

View File

@@ -11,7 +11,7 @@
#define BOOST_PROCESS_POSIX_SEARCH_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/filesystem.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include <stdexcept>
@@ -20,15 +20,19 @@
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
inline boost::process::filesystem::path search_path(
const boost::process::filesystem::path &filename,
const std::vector<boost::process::filesystem::path> &path)
{
for (const boost::filesystem::path & pp : path)
for (const boost::process::filesystem::path & pp : path)
{
auto p = pp / filename;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec;
bool file = boost::filesystem::is_regular_file(p, ec);
#endif
bool file = boost::process::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p;
}

View File

@@ -12,16 +12,16 @@
#include <boost/process/detail/config.hpp>
#include <boost/system/error_code.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
inline boost::filesystem::path shell_path()
inline boost::process::filesystem::path shell_path()
{
return "/bin/sh";
}
inline boost::filesystem::path shell_path(std::error_code &ec)
inline boost::process::filesystem::path shell_path(std::error_code &ec)
{
ec.clear();
return "/bin/sh";

View File

@@ -7,14 +7,18 @@
#ifndef BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#define BOOST_PROCESS_DETAIL_POSIX_SIGCHLD_SERVICE_HPP_
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/consign.hpp>
#include <boost/asio/append.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/asio/strand.hpp>
#include <boost/optional.hpp>
#include <signal.h>
#include <functional>
#include <sys/wait.h>
#include <list>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -23,8 +27,45 @@ class sigchld_service : public boost::asio::detail::service_base<sigchld_service
boost::asio::strand<boost::asio::io_context::executor_type> _strand{get_io_context().get_executor()};
boost::asio::signal_set _signal_set{get_io_context(), SIGCHLD};
std::vector<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
std::list<std::pair<::pid_t, std::function<void(int, std::error_code)>>> _receivers;
inline void _handle_signal(const boost::system::error_code & ec);
struct initiate_async_wait_op
{
sigchld_service * self;
template<typename Initiation>
void operator()(Initiation && init, ::pid_t pid)
{
// check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
{
auto ec = get_last_error();
boost::asio::post(
self->_strand,
asio::append(std::forward<Initiation>(init), pid_res, ec));
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
boost::asio::post(
self->_strand,
boost::asio::append(std::forward<Initiation>(init), status, std::error_code{}));
else //still running
{
sigchld_service * self_ = self;
if (self->_receivers.empty())
self->_signal_set.async_wait(
boost::asio::bind_executor(
self->_strand,
[self_](const boost::system::error_code &ec, int)
{
self_->_handle_signal(ec);
}));
self->_receivers.emplace_back(pid, init);
}
}
};
public:
sigchld_service(boost::asio::io_context & io_context)
: boost::asio::detail::service_base<sigchld_service>(io_context)
@@ -36,47 +77,10 @@ public:
void (int, std::error_code))
async_wait(::pid_t pid, SignalHandler && handler)
{
boost::asio::async_completion<
SignalHandler, void(boost::system::error_code)> init{handler};
auto & h = init.completion_handler;
boost::asio::dispatch(
_strand,
[this, pid, h]
{
//check if the child actually is running first
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
{
auto ec = get_last_error();
boost::asio::post(
_strand,
[pid_res, ec, h]
{
h(pid_res, ec);
});
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
boost::asio::post(
_strand,
[status, h]
{
h(status, {}); //successfully exited already
});
else //still running
{
if (_receivers.empty())
_signal_set.async_wait(
[this](const boost::system::error_code &ec, int)
{
boost::asio::dispatch(_strand, [this, ec]{this->_handle_signal(ec);});
});
_receivers.emplace_back(pid, h);
}
});
return init.result.get();
return boost::asio::async_initiate<
SignalHandler,
void(int, std::error_code)>(
initiate_async_wait_op{this}, handler, pid);
}
void shutdown() override
{

View File

@@ -13,6 +13,7 @@
#include <boost/process/detail/posix/handler.hpp>
#include <string>
#include <unistd.h>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace process { namespace detail { namespace posix {
@@ -26,7 +27,7 @@ struct start_dir_init : handler_base_ext
template <class PosixExecutor>
void on_exec_setup(PosixExecutor&) const
{
::chdir(s_.c_str());
boost::ignore_unused(::chdir(s_.c_str()));
}
const string_type & str() const {return s_;}
private:

View File

@@ -11,7 +11,7 @@
#include <vector>
#include <type_traits>
#include <initializer_list>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/process/detail/traits/decl.hpp>
namespace boost { namespace process { namespace detail {
@@ -53,12 +53,12 @@ template<> struct initializer_tag<std::initializer_list<const wchar_t *>> { type
template<> struct initializer_tag<shell_>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
};
template<> struct initializer_tag<boost::filesystem::path>
template<> struct initializer_tag<boost::process::filesystem::path>
{
typedef cmd_or_exe_tag<typename boost::filesystem::path::value_type> type;
typedef cmd_or_exe_tag<typename boost::process::filesystem::path::value_type> type;
};
template <typename Char>

View File

@@ -20,7 +20,7 @@ namespace boost { namespace process { namespace detail {
template<typename T> struct is_wchar_t : std::false_type {};
template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t>
template<> struct is_wchar_t<boost::process::filesystem::path> : std::is_same<typename boost::process::filesystem::path::value_type, wchar_t>
{
};

View File

@@ -69,7 +69,7 @@ template<typename Executor>
std::vector<::boost::process::detail::api::native_handle_type>
get_used_handles(Executor &exec)
{
std::vector<::boost::process::detail::api::native_handle_type> res;
std::vector<::boost::process::detail::api::native_handle_type> res = exec.get_used_handles();
foreach_used_handle(exec, [&](::boost::process::detail::api::native_handle_type handle){res.push_back(handle);});
return res;
}

View File

@@ -61,8 +61,12 @@ inline std::string build_args(const std::string & exe, std::vector<std::string>
arg += '"';
}
}
else
{
arg = "\"\"";
}
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;
@@ -105,8 +109,12 @@ inline std::wstring build_args(const std::wstring & exe, std::vector<std::wstrin
arg += '"';
}
}
else
{
arg = L"\"\"";
}
if (!st.empty())//first one does not need a preceeding space
if (!st.empty())//first one does not need a preceding space
st += L' ';
st += arg;
@@ -159,8 +167,13 @@ struct exe_cmd_init : handler_base_ext
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
#ifdef BOOST_PROCESS_USE_STD_FS
static std:: string get_shell(char) {return shell(). string(); }
static std::wstring get_shell(wchar_t) {return shell().wstring(); }
#else
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
#endif
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{

View File

@@ -158,7 +158,7 @@ basic_pipe<Char, Traits>::basic_pipe(const std::string & name)
::boost::process::detail::throw_last_error("create_named_pipe() failed");
::boost::winapi::HANDLE_ sink = boost::winapi::create_file(
name.c_str(),
name_.c_str(),
::boost::winapi::GENERIC_WRITE_, 0, nullptr,
OPEN_EXISTING_,
FILE_FLAG_OVERLAPPED_, //to allow read

View File

@@ -81,7 +81,7 @@ struct child_handle
{
::boost::winapi::BOOL_ value;
if (!::boost::winapi::IsProcessInJob(proc_info.hProcess, nullptr, &value))
throw_last_error("IsProcessinJob Failed");
throw_last_error("IsProcessInJob Failed");
return value!=0;
}
bool in_group(std::error_code &ec) const noexcept

View File

@@ -73,8 +73,8 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
if (size == sizeof(buf)) //the return size gives the size without the null, so I know this went wrong
{
/*limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768 so it is a multiple of 4096.
/* limit defined here https://msdn.microsoft.com/en-us/library/windows/desktop/ms683188(v=vs.85).aspx
* but I used 32768, so it is a multiple of 4096.
*/
constexpr static std::size_t max_size = 32768;
//Handle variables longer then buf.
@@ -90,12 +90,12 @@ inline auto native_environment_impl<Char>::get(const pointer_type id) -> string_
::boost::process::detail::throw_last_error("GetEnvironmentVariable() failed");
else
return std::basic_string<Char>(
buf.data(), buf.data()+ size + 1);
buf.data(), buf.data()+ size);
}
}
return std::basic_string<Char>(buf, buf+size+1);
return std::basic_string<Char>(buf, buf+size);
}
template<typename Char>
@@ -232,6 +232,8 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
return string_type(_data.data());
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.
@@ -271,7 +273,7 @@ template<typename Char>
inline void basic_environment_impl<Char>::reset(const string_type &id)
{
//ok, we need to check the size of data first
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
if (id.size() >= _data.size()) //ok, so it is impossible id is in there.
return;
//check if it's the first one, spares us the search.

View File

@@ -10,7 +10,7 @@
#include <boost/winapi/handles.hpp>
#include <boost/winapi/file_management.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/core/exchange.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
@@ -40,7 +40,7 @@ struct file_descriptor
}
file_descriptor() = default;
file_descriptor(const boost::filesystem::path& p, mode_t mode = read_write)
file_descriptor(const boost::process::filesystem::path& p, mode_t mode = read_write)
: file_descriptor(p.native(), mode)
{
}

View File

@@ -11,6 +11,8 @@
#include <boost/process/detail/windows/handle_workaround.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/winapi/handles.hpp>
#include <boost/winapi/handle_info.hpp>
namespace boost { namespace process { namespace detail {
@@ -162,7 +164,7 @@ struct limit_handles_ : handler_base_ext
}
template<typename Executor>
void on_sucess(Executor & exec) const
void on_success(Executor & exec) const
{
for (auto handle : handles_with_inherit_flag)
::boost::winapi::SetHandleInformation(handle, ::boost::winapi::HANDLE_FLAG_INHERIT_, ::boost::winapi::HANDLE_FLAG_INHERIT_);

View File

@@ -14,6 +14,8 @@
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/system/error_code.hpp>
namespace boost { namespace process { namespace detail { namespace windows {

View File

@@ -15,11 +15,11 @@
#include <boost/winapi/handles.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/system/error_code.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
template<int p1, int p2>
struct pipe_out : public ::boost::process::detail::handler_base, ::boost::process::detail::uses_handles
{

View File

@@ -11,8 +11,7 @@
#define BOOST_PROCESS_WINDOWS_SEARCH_PATH_HPP
#include <boost/process/detail/config.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/system/error_code.hpp>
#include <string>
#include <stdexcept>
@@ -24,9 +23,9 @@
namespace boost { namespace process { namespace detail { namespace windows {
inline boost::filesystem::path search_path(
const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> &path)
inline boost::process::filesystem::path search_path(
const boost::process::filesystem::path &filename,
const std::vector<boost::process::filesystem::path> &path)
{
const ::boost::process::wnative_environment ne{};
typedef typename ::boost::process::wnative_environment::const_entry_type value_type;
@@ -36,7 +35,9 @@ inline boost::filesystem::path search_path(
[&](const value_type & e)
{return id == ::boost::to_upper_copy(e.get_name(), ::boost::process::detail::process_locale());});
auto extensions_in = itr->to_vector();
std::vector<std::wstring> extensions_in;
if (itr != ne.cend())
extensions_in = itr->to_vector();
std::vector<std::wstring> extensions((extensions_in.size() * 2) + 1);
@@ -55,15 +56,19 @@ inline boost::filesystem::path search_path(
for (auto & ext : extensions)
boost::to_lower(ext);
for (const boost::filesystem::path & pp_ : path)
for (const boost::process::filesystem::path & pp_ : path)
{
auto p = pp_ / filename;
for (boost::filesystem::path ext : extensions)
for (boost::process::filesystem::path ext : extensions)
{
boost::filesystem::path pp_ext = p;
boost::process::filesystem::path pp_ext = p;
pp_ext += ext;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec;
bool file = boost::filesystem::is_regular_file(pp_ext, ec);
#endif
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
if (!ec && file &&
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))
{

View File

@@ -12,29 +12,29 @@
#include <boost/process/detail/config.hpp>
#include <system_error>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#include <boost/winapi/basic_types.hpp>
#include <boost/winapi/get_system_directory.hpp>
namespace boost { namespace process { namespace detail { namespace windows {
inline boost::filesystem::path shell_path()
inline boost::process::filesystem::path shell_path()
{
::boost::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
if (!size)
throw_last_error("GetSystemDirectory() failed");
boost::filesystem::path p = sysdir;
boost::process::filesystem::path p = sysdir;
return p / "cmd.exe";
}
inline boost::filesystem::path shell_path(std::error_code &ec) noexcept
inline boost::process::filesystem::path shell_path(std::error_code &ec) noexcept
{
::boost::winapi::WCHAR_ sysdir[260];
unsigned int size = ::boost::winapi::get_system_directory(sysdir, sizeof(sysdir));
boost::filesystem::path p;
boost::process::filesystem::path p;
if (!size)
ec = std::error_code(
::boost::winapi::GetLastError(),

View File

@@ -6,6 +6,7 @@
#ifndef BOOST_PROCESS_DETAIL_ENV_HPP_
#define BOOST_PROCESS_DETAIL_ENV_HPP_
#include <boost/process/detail/traits/wchar_t.hpp>
#include <boost/process/environment.hpp>
#include <boost/none.hpp>
@@ -436,7 +437,7 @@ for both `id` and `value`.
\subsubsection env_reset Reset variables
Reseting signle variables can be done in the following way:
Resetting single variables can be done in the following way:
\code{.cpp}
env[id] = boost::none;

View File

@@ -11,7 +11,7 @@
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/environment.hpp>
@@ -263,7 +263,9 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
@@ -275,7 +277,9 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
@@ -288,7 +292,10 @@ public:
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
const std::size_t len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) <
static_cast<typename string_type::iterator::difference_type>(len))
&& std::equal(st1.begin(), st1.end(), *p))
return 1u;
p++;
}
@@ -672,7 +679,7 @@ inline native_environment environment() { return ::boost::process:: native_env
///Get the enviroment of the current process.
inline wnative_environment wenvironment() { return ::boost::process::wnative_environment(); }
///Get the path environment variable of the current process runs.
inline std::vector<boost::filesystem::path> path()
inline std::vector<boost::process::filesystem::path> path()
{
#if defined(BOOST_WINDOWS_API)
const ::boost::process::wnative_environment ne{};
@@ -693,7 +700,7 @@ inline std::vector<boost::filesystem::path> path()
auto vec = itr->to_vector();
std::vector<boost::filesystem::path> val;
std::vector<boost::process::filesystem::path> val;
val.resize(vec.size());
std::copy(vec.begin(), vec.end(), val.begin());

View File

@@ -36,15 +36,15 @@ namespace detail {
struct exe_
{
template<typename = void>
inline exe_setter_<typename boost::filesystem::path::value_type> operator()(const boost::filesystem::path & pth) const
inline exe_setter_<typename boost::process::filesystem::path::value_type> operator()(const boost::process::filesystem::path & pth) const
{
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
return exe_setter_<typename boost::process::filesystem::path::value_type>(pth.native());
}
template<typename = void>
inline exe_setter_<typename boost::filesystem::path::value_type> operator=(const boost::filesystem::path & pth) const
inline exe_setter_<typename boost::process::filesystem::path::value_type> operator=(const boost::process::filesystem::path & pth) const
{
return exe_setter_<typename boost::filesystem::path::value_type>(pth.native());
return exe_setter_<typename boost::process::filesystem::path::value_type>(pth.native());
}
@@ -79,7 +79,7 @@ The overload form applies when to the first, when several strings are passed to
function.
The following expressions are valid, with `value` being either a C-String or
a `std::basic_string` with `char` or `wchar_t` or a `boost::filesystem::path`.
a `std::basic_string` with `char` or `wchar_t` or a `boost::process::filesystem::path`.
\code{.cpp}
exe="value";

View File

@@ -70,7 +70,7 @@ 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.
///This handler is invoked if an error occurred. 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;

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2021 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_FILESYSTEM_HPP
#define BOOST_PROCESS_FILESYSTEM_HPP
#ifdef BOOST_PROCESS_USE_STD_FS
#include <filesystem>
#else
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#endif
namespace boost
{
namespace process
{
#ifdef BOOST_PROCESS_USE_STD_FS
namespace filesystem = std::filesystem;
#else
namespace filesystem = boost::filesystem;
#endif
}
}
#endif //BOOST_PROCESS_FILESYSTEM_HPP

View File

@@ -122,9 +122,11 @@ public:
{
boost::process::detail::api::wait(_group_handle, ec);
}
#if !defined(BOOST_PROCESS_NO_DEPRECATED)
/** Wait for the process group to exit for period of time.
* \return True if all child processes exited while waiting.*/
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
{
return boost::process::detail::api::wait_for(_group_handle, rel_time);
@@ -132,6 +134,7 @@ public:
/** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
template< class Rep, class Period >
BOOST_DEPRECATED("wait_for is unreliable")
bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
{
return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
@@ -140,17 +143,19 @@ public:
/** Wait for the process group to exit until a point in time.
* \return True if all child processes exited while waiting.*/
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
{
return boost::process::detail::api::wait_until(_group_handle, timeout_time);
}
/** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
template< class Clock, class Duration >
BOOST_DEPRECATED("wait_until is unreliable")
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
{
return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
}
#endif
///Check if the group has a valid handle.
bool valid() const
{

View File

@@ -82,7 +82,7 @@ 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
* The limit_handles property sets all properties to be inherited only explicitly. 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.

View File

@@ -60,9 +60,9 @@ namespace boost {
The library allows full redirection of streams to files as shown below.
\code{.cpp}
boost::filesystem::path log = "my_log_file.txt";
boost::filesystem::path input = "input.txt";
boost::filesystem::path output = "output.txt";
boost::process::filesystem::path log = "my_log_file.txt";
boost::process::filesystem::path input = "input.txt";
boost::process::filesystem::path output = "output.txt";
system("my_prog", std_out>output, std_in<input, std_err>log);
\endcode
@@ -152,13 +152,13 @@ struct std_in_
api::null_in operator=(const null_t &) const {return api::null_in();}
api::null_in operator<(const null_t &) const {return api::null_in();}
api::file_in operator=(const boost::filesystem::path &p) const {return p;}
api::file_in operator=(const boost::process::filesystem::path &p) const {return p;}
api::file_in operator=(const std::string & p) const {return p;}
api::file_in operator=(const std::wstring &p) const {return p;}
api::file_in operator=(const char * p) const {return p;}
api::file_in operator=(const wchar_t * p) const {return p;}
api::file_in operator<(const boost::filesystem::path &p) const {return p;}
api::file_in operator<(const boost::process::filesystem::path &p) const {return p;}
api::file_in operator<(const std::string &p) const {return p;}
api::file_in operator<(const std::wstring &p) const {return p;}
api::file_in operator<(const char*p) const {return p;}
@@ -209,13 +209,13 @@ struct std_out_
api::null_out<p1,p2> operator=(const null_t &) const {return api::null_out<p1,p2>();}
api::null_out<p1,p2> operator>(const null_t &) const {return api::null_out<p1,p2>();}
api::file_out<p1,p2> operator=(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator=(const boost::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator=(const std::string &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator=(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator=(const char * p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator=(const wchar_t * p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator>(const boost::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator>(const boost::process::filesystem::path &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator>(const std::string &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator>(const std::wstring &p) const {return api::file_out<p1,p2>(p);}
api::file_out<p1,p2> operator>(const char * p) const {return api::file_out<p1,p2>(p);}
@@ -282,7 +282,7 @@ This property allows to set the input stream for the child process.
The file I/O simple redirects the stream to a file, for which the possible types are
- `boost::filesystem::path`
- `boost::process::filesystem::path`
- `std::basic_string<char_type>`
- `const char_type*`
- `FILE*`
@@ -424,7 +424,7 @@ This property allows to set the output stream for the child process.
The file I/O simple redirects the stream to a file, for which the possible types are
- `boost::filesystem::path`
- `boost::process::filesystem::path`
- `std::basic_string<char_type>`
- `const char_type*`
- `FILE*`

View File

@@ -123,8 +123,14 @@ struct basic_pipebuf : std::basic_streambuf<CharT, Traits>
///Destructor -> writes the frest of the data
~basic_pipebuf()
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
try
{
if (basic_pipebuf::is_open())
basic_pipebuf::overflow(Traits::eof());
}
catch (process_error & )
{
}
}
///Move construct from a pipe.

View File

@@ -35,7 +35,7 @@ namespace boost {
namespace boost { namespace process {
///Namespace containing the posix exensions.
///Namespace containing the posix extensions.
namespace posix {
/** This property lets you modify file-descriptors other than the standard ones (0,1,2).

View File

@@ -44,8 +44,8 @@ namespace boost { namespace process {
* \returns the absolute path to the executable filename or an
* empty string if filename isn't found
*/
inline boost::filesystem::path search_path(const boost::filesystem::path &filename,
const std::vector<boost::filesystem::path> path = ::boost::this_process::path())
inline boost::process::filesystem::path search_path(const boost::process::filesystem::path &filename,
const std::vector<boost::process::filesystem::path> path = ::boost::this_process::path())
{
return ::boost::process::detail::api::search_path(filename, path);
}

View File

@@ -44,18 +44,18 @@ struct shell_
{
constexpr shell_() {}
boost::filesystem::path operator()() const
boost::process::filesystem::path operator()() const
{
return boost::process::detail::api::shell_path();
}
boost::filesystem::path operator()(std::error_code & ec) const noexcept
boost::process::filesystem::path operator()(std::error_code & ec) const noexcept
{
return boost::process::detail::api::shell_path(ec);
}
};
template<>
struct is_wchar_t<shell_> : is_wchar_t<boost::filesystem::path>
struct is_wchar_t<shell_> : is_wchar_t<boost::process::filesystem::path>
{
};

View File

@@ -23,7 +23,7 @@
#include <boost/process/detail/config.hpp>
#include <string>
#include <boost/filesystem/path.hpp>
#include <boost/process/filesystem.hpp>
/** \file boost/process/start_dir.hpp
*
@@ -53,8 +53,8 @@ struct start_dir_
api::start_dir_init<Char> operator()(std::basic_string<Char> && s) const {return {std::move(s)}; }
template<typename Char>
api::start_dir_init<Char> operator()(const Char* s) const {return {s}; }
api::start_dir_init<typename boost::filesystem::path::value_type>
operator()(const boost::filesystem::path & st) const {return {st.native()}; }
api::start_dir_init<typename boost::process::filesystem::path::value_type>
operator()(const boost::process::filesystem::path & st) const {return {st.native()}; }
template<typename Char>
api::start_dir_init<Char> operator= (const std::basic_string<Char> & st) const {return {st}; }
@@ -62,8 +62,8 @@ struct start_dir_
api::start_dir_init<Char> operator= (std::basic_string<Char> && s) const {return {std::move(s)}; }
template<typename Char>
api::start_dir_init<Char> operator= (const Char* s) const {return {s}; }
api::start_dir_init<typename boost::filesystem::path::value_type>
operator= (const boost::filesystem::path & st) const {return {st.native()}; }
api::start_dir_init<typename boost::process::filesystem::path::value_type>
operator= (const boost::process::filesystem::path & st) const {return {st.native()}; }
};
@@ -100,7 +100,7 @@ start_dir=path
start_dir(path)
\endcode
It can be used with `std::string`, `std::wstring` and `boost::filesystem::path`.
It can be used with `std::string`, `std::wstring` and `boost::process::filesystem::path`.
*/

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_HPP
#define BOOST_PROCESS_V2_HPP
#include <boost/process/v2/error.hpp>
#include <boost/process/v2/environment.hpp>
#include <boost/process/v2/execute.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <boost/process/v2/pid.hpp>
#include <boost/process/v2/popen.hpp>
#include <boost/process/v2/process_handle.hpp>
#include <boost/process/v2/process.hpp>
#include <boost/process/v2/start_dir.hpp>
#include <boost/process/v2/stdio.hpp>
#endif //BOOST_PROCESS_V2_HPP

View File

@@ -0,0 +1,240 @@
//
// boost/process/v2/bind_launcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#define BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/default_launcher.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<std::size_t ... Idx>
struct index_sequence { };
template<std::size_t Size, typename T>
struct make_index_sequence_impl;
template<std::size_t Size, std::size_t ... Idx>
struct make_index_sequence_impl<Size, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = typename make_index_sequence_impl<Size - 1u, index_sequence<Size - 1u, Idx...>>::type;
};
template<std::size_t ... Idx>
struct make_index_sequence_impl<0u, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = index_sequence<Idx...>;
};
template<std::size_t Cnt>
struct make_index_sequence
{
using type = typename make_index_sequence_impl<Cnt, index_sequence<>>::type;
};
template<std::size_t Cnt>
using make_index_sequence_t = typename make_index_sequence<Cnt>::type;
}
/** @brief Utility class to bind initializers to a launcher
* @tparam Launcher The inner launcher to be used
* @tparam ...Init The initializers to be prepended.
*
* This can be used when multiple processes shared some settings,
* e.g.
*
*/
template<typename Launcher, typename ... Init>
struct bound_launcher
{
template<typename Launcher_, typename ... Init_>
bound_launcher(Launcher_ && l, Init_ && ... init) :
launcher_(std::forward<Launcher_>(l)), init_(std::forward<Init_>(init)...)
{
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context, ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec),
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec), ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
private:
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context, ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec),
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec), ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
Launcher launcher_;
std::tuple<Init...> init_;
};
template<typename Launcher, typename ... Init>
auto bind_launcher(Launcher && launcher, Init && ... init)
-> bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>
{
return bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>(
std::forward<Launcher>(launcher),
std::forward<Init>(init)...);
}
/// @brief @overload bind_launcher(Launcher && launcher, Init && init)
/// @tparam ...Init The initializer types to bind to the default_launcher.
/// @param ...init The initializers types to bind to the default_launcher.
/// @return The new default_launcher.
template<typename ... Init>
auto bind_default_launcher(Init && ... init)
-> bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>
{
return bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>(
default_process_launcher(),
std::forward<Init>(init)...);
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif // BOOST_PROCESS_V2_BIND_LAUNCHER_HPP

View File

@@ -0,0 +1,232 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_CSTRING_REF_HPP
#define BOOST_PROCESS_V2_CSTRING_REF_HPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <string_view>
#else
#include <boost/utility/string_view.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
BOOST_CONSTEXPR static const char* null_char_(char) {return "";}
BOOST_CONSTEXPR static const wchar_t* null_char_(wchar_t) {return L"";}
BOOST_CONSTEXPR static const char16_t* null_char_(char16_t) {return u"";}
BOOST_CONSTEXPR static const char32_t* null_char_(char32_t) {return U"";}
#if defined(BOOST_PROCESS_V2_HAS_CHAR8_T)
BOOST_CONSTEXPR static const char8_t* null_char_(char8_t) {return u8"";}
#endif
}
#if defined(BOOST_PROCESS_V2_STANDALONE)
using std::basic_string_view;
using std:: string_view;
using std:: wstring_view;
#else
using boost::basic_string_view;
using boost:: string_view;
using boost:: wstring_view;
#endif
/// Small wrapper for a null-terminated string that can be directly passed to C APIS
/** This ref can only be modified by moving the front pointer. It does not store the
* size, but can detect values that can directly be passed to system APIs.
*
* It can be constructed from a `char*` pointer or any class that has a `c_str()`
* member function, e.g. std::string or boost::static_string.
*
*/
template<typename CharT, typename Traits = std::char_traits<CharT>>
struct basic_cstring_ref
{
using value_type = CharT;
using traits_type = Traits;
BOOST_CONSTEXPR basic_cstring_ref() noexcept : view_(detail::null_char_(value_type{})) {}
BOOST_CONSTEXPR basic_cstring_ref(std::nullptr_t) = delete;
BOOST_CONSTEXPR basic_cstring_ref( const value_type* s ) : view_(s) {}
template<typename Source,
typename =
typename std::enable_if<
std::is_same<const value_type,
typename std::remove_pointer<decltype(std::declval<Source>().c_str())>::type
>::value>::type>
BOOST_CONSTEXPR basic_cstring_ref(Source && src) : view_(src.c_str()) {}
BOOST_CONSTEXPR typename basic_string_view<value_type, Traits>::const_pointer c_str() const BOOST_NOEXCEPT
{
return this->data();
}
using string_view_type = basic_string_view<value_type, Traits>;
constexpr operator string_view_type() const {return view_;}
using pointer = CharT *;
using const_pointer = const CharT *;
using reference = CharT &;
using const_reference = const CharT &;
using const_iterator = const_pointer;
using iterator = const_iterator;
using const_reverse_iterator = typename std::reverse_iterator<const_iterator>;
using reverse_iterator = typename std::reverse_iterator<iterator>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
static BOOST_CONSTEXPR size_type npos = -1;
BOOST_CONSTEXPR const_iterator begin() const BOOST_NOEXCEPT {return view_;};
BOOST_CONSTEXPR const_iterator end() const BOOST_NOEXCEPT {return view_ + length();};
BOOST_CONSTEXPR const_iterator cbegin() const BOOST_NOEXCEPT {return view_;};
BOOST_CONSTEXPR const_iterator cend() const BOOST_NOEXCEPT {return view_ + length();};
BOOST_CONSTEXPR const_reverse_iterator rbegin() const BOOST_NOEXCEPT {return reverse_iterator(view_ + length());};
BOOST_CONSTEXPR const_reverse_iterator rend() const BOOST_NOEXCEPT {return reverse_iterator(view_);};
BOOST_CONSTEXPR const_reverse_iterator crbegin() const BOOST_NOEXCEPT {return reverse_iterator(view_ + length());};
BOOST_CONSTEXPR const_reverse_iterator crend() const BOOST_NOEXCEPT {return reverse_iterator(view_);};
BOOST_CONSTEXPR size_type size() const BOOST_NOEXCEPT {return length(); }
BOOST_CONSTEXPR size_type length() const BOOST_NOEXCEPT {return traits_type::length(view_); }
BOOST_CONSTEXPR size_type max_size() const BOOST_NOEXCEPT {return (std::numeric_limits<std::size_t>::max)() / sizeof(CharT); }
BOOST_ATTRIBUTE_NODISCARD BOOST_CONSTEXPR bool empty() const BOOST_NOEXCEPT {return *view_ == *detail::null_char_(CharT{}); }
BOOST_CONSTEXPR const_reference operator[](size_type pos) const {return view_[pos] ;}
BOOST_CXX14_CONSTEXPR const_reference at(size_type pos) const
{
if (pos >= size())
throw_exception(std::out_of_range("cstring-view out of range"));
return view_[pos];
}
BOOST_CONSTEXPR const_reference front() const {return *view_;}
BOOST_CONSTEXPR const_reference back() const {return view_[length() - 1];}
BOOST_CONSTEXPR const_pointer data() const BOOST_NOEXCEPT {return view_;}
BOOST_CXX14_CONSTEXPR void remove_prefix(size_type n) {view_ = view_ + n;}
void swap(basic_cstring_ref& s) BOOST_NOEXCEPT {std::swap(view_, s.view_);}
size_type copy(value_type* s, size_type n, size_type pos = 0) const
{
return traits_type::copy(s, view_ + pos, n) - view_;
}
BOOST_CONSTEXPR basic_cstring_ref substr(size_type pos = 0) const
{
return basic_cstring_ref(view_ + pos);
}
BOOST_CONSTEXPR string_view_type substr(size_type pos, size_type length) const
{
return string_view_type(view_).substr(pos, length);
}
BOOST_CXX14_CONSTEXPR int compare(basic_cstring_ref x) const BOOST_NOEXCEPT
{
auto idx = 0u;
for (; view_[idx] != null_char_()[0] && x[idx] != null_char_()[0]; idx++)
if (!traits_type::eq(view_[idx], x[idx]))
return traits_type::lt(view_[idx], x[idx]) ? -1 : 1;
return traits_type::to_int_type(view_[idx]) -
traits_type::to_int_type(x[idx]); // will compare to null char of either.
}
BOOST_CXX14_CONSTEXPR bool starts_with(string_view_type x) const BOOST_NOEXCEPT
{
if (x.empty())
return true;
auto idx = 0u;
for (; view_[idx] != null_char_()[0] && idx < x.size(); idx++)
if (!traits_type::eq(view_[idx], x[idx]))
return false;
return idx == x.size() || view_[idx] != null_char_()[0];
}
BOOST_CONSTEXPR bool starts_with(value_type x) const BOOST_NOEXCEPT
{
return traits_type::eq(view_[0], x);
}
BOOST_CXX14_CONSTEXPR size_type find( CharT ch, size_type pos = 0 ) const BOOST_NOEXCEPT
{
for (auto p = view_ + pos; *p != *null_char_(); p++)
if (traits_type::eq(*p, ch))
return p - view_;
return npos;
}
friend BOOST_CXX14_CONSTEXPR bool operator==(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT
{
std::size_t idx = 0u;
for (idx = 0u; x[idx] != null_char_()[0] && y[idx] != null_char_()[0]; idx++)
if (!traits_type::eq(x[idx], y[idx]))
return false;
return x[idx] == y[idx];
}
friend BOOST_CXX14_CONSTEXPR bool operator!=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT
{
std::size_t idx = 0u;
for (idx = 0u; x[idx] != null_char_()[0] &&
y[idx] != null_char_()[0]; idx++)
if (!traits_type::eq(x[idx], y[idx]))
return true;
return x[idx] != y[idx];
}
friend BOOST_CXX14_CONSTEXPR bool operator< (basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) < 0;}
friend BOOST_CXX14_CONSTEXPR bool operator> (basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) > 0;}
friend BOOST_CXX14_CONSTEXPR bool operator<=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) <= 0;}
friend BOOST_CXX14_CONSTEXPR bool operator>=(basic_cstring_ref x, basic_cstring_ref y) BOOST_NOEXCEPT {return x.compare(y) >= 0;}
// modifiers
void clear() BOOST_NOEXCEPT { view_ = null_char_(); } // Boost extension
std::basic_string<value_type, traits_type> to_string() const {
return std::basic_string<CharT, Traits>(begin(), end());
}
template<typename Allocator>
std::basic_string<value_type, traits_type, Allocator> to_string(const Allocator& a) const {
return std::basic_string<value_type, traits_type, Allocator>(begin(), end(), a);
}
private:
BOOST_CONSTEXPR static const_pointer null_char_() {return detail::null_char_(CharT{});}
const_pointer view_;
};
template<class charT, class traits>
inline std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os,
const basic_cstring_ref<charT,traits>& str)
{
return os << static_cast<basic_string_view<charT, traits>>(str);
}
template <class charT, class traits>
std::size_t hash_value(basic_string_view<charT, traits> s) {
return boost::hash_range(s.begin(), s.end());
}
using cstring_ref = basic_cstring_ref<char>;
using wcstring_ref = basic_cstring_ref<wchar_t>;
using u16cstring_ref = basic_cstring_ref<char16_t>;
using u32cstring_ref = basic_cstring_ref<char32_t>;
#if defined(BOOST_PROCESS_V2_HAS_CHAR8_T)
using u8cstring_ref = basic_cstring_ref<char8_t>;
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_CSTRING_REF_HPP

View File

@@ -0,0 +1,66 @@
//
// boost/process/v2/default_launcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_DEFAULT_LAUNCHER_HPP
#define BOOST_PROCESS_V2_DEFAULT_LAUNCHER_HPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/windows/default_launcher.hpp>
#else
#if defined(BOOST_PROCESS_V2_PDFORK)
#include <boost/process/v2/posix/pdfork_launcher.hpp>
#else
#include <boost/process/v2/posix/default_launcher.hpp>
#endif
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(GENERATING_DOCUMENTATION)
/// The default launcher for processes.
/** This launcher will be used by process if a
* process is launched through the constructor:
*
* @code {.cpp}
* process proc("test", {});
* // equivalent to
* process prod = default_launcher()("test", {});
* @endcode
*
*/
typedef implementation_defined default_process_launcher;
#else
#if defined(BOOST_PROCESS_V2_WINDOWS)
typedef windows::default_launcher default_process_launcher;
#else
#if defined(BOOST_PROCESS_V2_PDFORK)
typedef posix::pdfork_launcher default_process_launcher;
#else
typedef posix::default_launcher default_process_launcher;
#endif
#endif
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/default_launcher.ipp>
#endif
#endif //BOOST_PROCESS_V2_DEFAULT_LAUNCHER_HPP

View File

@@ -0,0 +1,180 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
#define BOOST_PROCESS_V2_DETAIL_CONFIG_HPP
#if defined(BOOST_PROCESS_V2_STANDALONE)
#define BOOST_PROCESS_V2_ASIO_NAMESPACE asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <asio/detail/config.hpp>
#include <system_error>
#include <filesystem>
#include <string_view>
#include <iomanip>
#include <optional>
#if defined(ASIO_WINDOWS)
#define BOOST_PROCESS_V2_WINDOWS 1
// Windows: suppress definition of "min" and "max" macros.
#if !defined(NOMINMAX)
# define NOMINMAX 1
#endif
#endif
#if defined(ASIO_HAS_UNISTD_H)
#define BOOST_PROCESS_V2_POSIX 1
#endif
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace process_v2 {
#define BOOST_PROCESS_V2_END_NAMESPACE }
#define BOOST_PROCESS_V2_NAMESPACE process_v2
#else
#define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <boost/config.hpp>
#include <boost/io/quoted.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_category.hpp>
#include <boost/system/system_error.hpp>
#include <boost/optional.hpp>
#if defined(BOOST_WINDOWS_API)
#define BOOST_PROCESS_V2_WINDOWS 1
// Windows: suppress definition of "min" and "max" macros.
#if !defined(NOMINMAX)
# define NOMINMAX 1
#endif
#endif
#if defined(BOOST_POSIX_API)
#define BOOST_PROCESS_V2_POSIX 1
#endif
#if !defined(BOOST_PROCESS_V2_WINDOWS) && !defined(BOOST_POSIX_API)
#error Unsupported operating system
#endif
#if defined(BOOST_PROCESS_USE_STD_FS)
#include <filesystem>
#else
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#endif
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
#define BOOST_PROCESS_V2_END_NAMESPACE } } }
#define BOOST_PROCESS_V2_NAMESPACE boost::process::v2
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_STANDALONE)
using std::error_code ;
using std::error_category ;
using std::system_category ;
using std::system_error ;
namespace filesystem = std::filesystem;
using std::quoted;
using std::optional;
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category()); \
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) ec.assign(__VA_ARGS__);
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error()); \
#else
using boost::system::error_code ;
using boost::system::error_category ;
using boost::system::system_category ;
using boost::system::system_error ;
using boost::io::quoted;
using boost::optional;
#ifdef BOOST_PROCESS_USE_STD_FS
namespace filesystem = std::filesystem;
#else
namespace filesystem = boost::filesystem;
#endif
#define BOOST_PROCESS_V2_RETURN_EC(ev) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
return ::BOOST_PROCESS_V2_NAMESPACE::error_code(ev, ::BOOST_PROCESS_V2_NAMESPACE::system_category(), &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_EC(ec, ...) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(__VA_ARGS__, &loc##__LINE__); \
}
#define BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec) \
{ \
static constexpr auto loc##__LINE__((BOOST_CURRENT_LOCATION)); \
ec.assign(::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error(), &loc##__LINE__); \
}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#ifndef BOOST_PROCESS_V2_HEADER_ONLY
# ifndef BOOST_PROCESS_V2_SEPARATE_COMPILATION
# define BOOST_PROCESS_V2_HEADER_ONLY 1
# endif
#endif
#if BOOST_PROCESS_V2_DOXYGEN
# define BOOST_PROCESS_V2_DECL
#elif defined(BOOST_PROCESS_V2_HEADER_ONLY)
# define BOOST_PROCESS_V2_DECL inline
#else
# define BOOST_PROCESS_V2_DECL
#endif
#if defined(BOOST_PROCESS_V2_POSIX)
#if defined(__linux__) && !defined(BOOST_PROCESS_V2_DISABLE_PIDFD_OPEN)
#include <sys/syscall.h>
#if defined(SYS_pidfd_open)
#define BOOST_PROCESS_V2_PIDFD_OPEN 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
#endif
#if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
#define BOOST_PROCESS_V2_PDFORK 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
#else
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif
#endif //BOOST_PROCESS_V2_DETAIL_CONFIG_HPP

View File

@@ -0,0 +1,80 @@
//
// process/environment/detail/environment_posix.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_POSIX_HPP
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_POSIX_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#if defined(__APPLE__) || defined(__MACH__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun)
extern "C" { extern char **environ; }
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
using char_type = char;
template<typename Char>
using key_char_traits = std::char_traits<Char>;
template<typename Char>
using value_char_traits = std::char_traits<Char>;
constexpr char_type equality_sign = '=';
constexpr char_type delimiter = ':';
namespace detail
{
BOOST_PROCESS_V2_DECL
basic_cstring_ref<char_type, value_char_traits<char>>
get(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec);
BOOST_PROCESS_V2_DECL
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
error_code & ec);
BOOST_PROCESS_V2_DECL
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec);
}
using native_handle_type = const char * const *;
using native_iterator = native_handle_type;
namespace detail
{
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
struct native_handle_deleter
{
void operator()(native_handle_type) const {}
};
BOOST_PROCESS_V2_DECL native_iterator next(native_handle_type nh);
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
inline const char_type * dereference(native_iterator iterator) {return *iterator;}
BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_code & ec);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif

View File

@@ -0,0 +1,212 @@
//
// process/environment/detail/environment_win.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <cwctype>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
using char_type = wchar_t;
template<typename Char>
struct key_char_traits
{
typedef Char char_type;
typedef typename std::char_traits<char_type>::int_type int_type;
typedef typename std::char_traits<char_type>::off_type off_type;
typedef typename std::char_traits<char_type>::pos_type pos_type;
typedef typename std::char_traits<char_type>::state_type state_type;
BOOST_CONSTEXPR static char to_lower(char c) {return std::tolower(to_int_type(c));}
BOOST_CONSTEXPR static wchar_t to_lower(wchar_t c) {return std::towlower(to_int_type(c));}
BOOST_CONSTEXPR static int_type to_lower(int_type i, char ) {return std::tolower(i);}
BOOST_CONSTEXPR static int_type to_lower(int_type i, wchar_t) {return std::towlower(i);}
BOOST_CONSTEXPR static
void assign(char_type& c1, const char_type& c2) BOOST_NOEXCEPT
{
c1 = c2;
}
BOOST_CONSTEXPR static
bool eq(char_type c1, char_type c2) BOOST_NOEXCEPT
{
return to_lower(c1) == to_lower(c2);
}
BOOST_CONSTEXPR static
bool lt(char_type c1, char_type c2) BOOST_NOEXCEPT
{
return to_lower(c1) < to_lower(c2);
}
BOOST_CONSTEXPR static
int compare(const char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
{
auto itrs = std::mismatch(s1, s1 + n, s2, &eq);
if (itrs.first == (s1 + n))
return 0;
auto c1 = to_lower(*itrs.first);
auto c2 = to_lower(*itrs.second);
return (c1 < c2 ) ? -1 : 1;
}
BOOST_CONSTEXPR static size_t length(const char* s) BOOST_NOEXCEPT { return std::strlen(s); }
BOOST_CONSTEXPR static size_t length(const wchar_t* s) BOOST_NOEXCEPT { return std::wcslen(s); }
BOOST_CONSTEXPR static
const char_type* find(const char_type* s, size_t n, const char_type& a) BOOST_NOEXCEPT
{
const char_type u = to_lower(a);
return std::find_if(s, s + n, [u](char_type c){return to_lower(c) == u;});
}
BOOST_CONSTEXPR static
char_type* move(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
{
if (s1 < s2)
return std::move(s2, s2 + n, s1);
else
return std::move_backward(s2, s2 + n, s1);
}
BOOST_CONSTEXPR static
char_type* copy(char_type* s1, const char_type* s2, size_t n) BOOST_NOEXCEPT
{
return std::copy(s2, s2 + n, s1);
}
BOOST_CONSTEXPR static
char_type* assign(char_type* s, size_t n, char_type a) BOOST_NOEXCEPT
{
std::fill(s, s + n, a);
return s +n;
}
BOOST_CONSTEXPR static
int_type not_eof(int_type c) BOOST_NOEXCEPT
{
return eq_int_type(c, eof()) ? ~eof() : c;
}
BOOST_CONSTEXPR static
char_type to_char_type(int_type c) BOOST_NOEXCEPT
{
return char_type(c);
}
BOOST_CONSTEXPR static
int_type to_int_type(char c) BOOST_NOEXCEPT
{
return int_type((unsigned char)c);
}
BOOST_CONSTEXPR static
int_type to_int_type(wchar_t c) BOOST_NOEXCEPT
{
return int_type((wchar_t)c);
}
BOOST_CONSTEXPR static
bool eq_int_type(int_type c1, int_type c2) BOOST_NOEXCEPT
{
return to_lower(c1, char_type()) == to_lower(c2, char_type());
}
BOOST_CONSTEXPR static inline int_type eof() BOOST_NOEXCEPT
{
return int_type(EOF);
}
};
namespace detail
{
template<typename Char>
std::size_t hash_step(std::size_t prev, Char c, key_char_traits<Char>)
{
return prev ^ (key_char_traits<Char>::to_lower(c) << 1);
}
}
template<typename Char>
using value_char_traits = std::char_traits<Char>;
BOOST_CONSTEXPR static char_type equality_sign = L'=';
BOOST_CONSTEXPR static char_type delimiter = L';';
using native_handle_type = wchar_t*;
using native_iterator = const wchar_t*;
namespace detail
{
BOOST_PROCESS_V2_DECL
std::basic_string<wchar_t, value_char_traits<wchar_t>> get(
basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
error_code & ec);
BOOST_PROCESS_V2_DECL
void set(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
basic_cstring_ref<wchar_t, value_char_traits<wchar_t>> value,
error_code & ec);
BOOST_PROCESS_V2_DECL
void unset(basic_cstring_ref<wchar_t, key_char_traits<wchar_t>> key,
error_code & ec);
BOOST_PROCESS_V2_DECL
std::basic_string<char, value_char_traits<char>> get(
basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec);
BOOST_PROCESS_V2_DECL
void set(basic_cstring_ref<char, key_char_traits<char>> key,
basic_cstring_ref<char, value_char_traits<char>> value,
error_code & ec);
BOOST_PROCESS_V2_DECL
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec);
BOOST_PROCESS_V2_DECL native_handle_type load_native_handle();
struct native_handle_deleter
{
native_handle_deleter() = default;
native_handle_deleter(const native_handle_deleter& ) = default;
BOOST_PROCESS_V2_DECL void operator()(native_handle_type nh) const;
};
inline const char_type * dereference(native_iterator iterator) {return iterator;}
BOOST_PROCESS_V2_DECL native_iterator next(native_iterator nh);
BOOST_PROCESS_V2_DECL native_iterator find_end(native_handle_type nh);
BOOST_PROCESS_V2_DECL bool is_executable(const filesystem::path & pth, error_code & ec);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/detail/impl/environment_win.ipp>
#elif defined(BOOST_PROCESS_V2_POSIX)
#include <boost/process/v2/detail/impl/environment_posix.ipp>
#else
#error Operating System not supported.
#endif
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_IPP

View File

@@ -0,0 +1,81 @@
//
// process/this_process/detail/environment_posix.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
#define BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/environment.hpp>
#include <boost/process/v2/cstring_ref.hpp>
#include <unistd.h>
#include <cstring>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
namespace detail
{
basic_cstring_ref<char_type, value_char_traits<char>> get(
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
auto res = ::getenv(key.c_str());
if (res == nullptr)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ENOENT, system_category())
return {};
}
return res;
}
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
error_code & ec)
{
if (::setenv(key.c_str(), value.c_str(), true))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
{
if (::unsetenv(key.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
native_handle_type load_native_handle() { return ::environ; }
native_iterator next(native_iterator nh)
{
return nh + 1;
}
native_iterator find_end(native_handle_type nh)
{
while (*nh != nullptr)
nh++;
return nh;
}
bool is_executable(const filesystem::path & p, error_code & ec)
{
return filesystem::is_regular_file(p, ec) && (::access(p.c_str(), X_OK) == 0);
}
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_ENVIRONMENT_WIN_HPP

View File

@@ -0,0 +1,142 @@
//
// process/this_process/detail/environment_win.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2021 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/environment_win.hpp>
#include <boost/process/v2/detail/impl/environment.ipp>
#include <boost/process/v2/detail/last_error.hpp>
#include <algorithm>
#include <cwctype>
#include <cstring>
#include <shellapi.h>
#include <boost/process/v2/cstring_ref.hpp>
#include <boost/process/v2/error.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace environment
{
namespace detail
{
std::basic_string<char_type, value_char_traits<char_type>> get(
basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
std::basic_string<char_type, value_char_traits<char_type>> buf;
std::size_t size = 0u;
do
{
buf.resize(buf.size() + 4096);
size = ::GetEnvironmentVariableW(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
}
while (size == buf.size());
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return buf;
}
void set(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
basic_cstring_ref<char_type, value_char_traits<char_type>> value,
error_code & ec)
{
if (!::SetEnvironmentVariableW(key.c_str(), value.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
std::basic_string<char, value_char_traits<char>> get(
basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
std::basic_string<char, value_char_traits<char>> buf;
std::size_t size = 0u;
do
{
buf.resize(buf.size() + 4096);
size = ::GetEnvironmentVariableA(key.c_str(), &buf.front(), static_cast<DWORD>(buf.size()));
}
while (size == buf.size());
buf.resize(size);
if (buf.size() == 0)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
return buf;
}
void set(basic_cstring_ref<char, key_char_traits<char>> key,
basic_cstring_ref<char, value_char_traits<char>> value,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), value.c_str()))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
native_handle_type load_native_handle() { return ::GetEnvironmentStringsW(); }
void native_handle_deleter::operator()(native_handle_type nh) const
{
::FreeEnvironmentStringsW(nh);
}
native_iterator next(native_iterator nh)
{
while (*nh != L'\0')
nh++;
return ++nh;
}
native_iterator find_end(native_handle_type nh)
{
while ((*nh != L'\0') || (*std::next(nh) != L'\0'))
nh++;
return ++nh;
}
bool is_executable(const filesystem::path & pth, error_code & ec)
{
return filesystem::is_regular_file(pth, ec) && SHGetFileInfoW(pth.native().c_str(), 0,0,0, SHGFI_EXETYPE);
}
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_ENVIRONMENT_WIN_IPP

View File

@@ -0,0 +1,34 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#else
#include <cerrno>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
error_code get_last_error()
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
return error_code(::GetLastError(), system_category());
#else
return error_code(errno, system_category());
#endif
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP

View File

@@ -0,0 +1,169 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_PROCESS_HANDLE_WINDOWS_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_PROCESS_HANDLE_WINDOWS_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/process_handle_windows.hpp>
#include <boost/process/v2/ext/detail/proc_info.hpp>
#include <windows.h>
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
extern "C"
{
LONG WINAPI NtResumeProcess(HANDLE ProcessHandle);
LONG WINAPI NtSuspendProcess(HANDLE ProcessHandle);
}
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
void get_exit_code_(
HANDLE handle,
native_exit_code_type & exit_code,
error_code & ec)
{
if (!::GetExitCodeProcess(handle, &exit_code))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
HANDLE open_process_(DWORD pid)
{
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (proc == nullptr)
{
error_code ec;
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
throw system_error(ec, "open_process()");
}
return proc;
}
void terminate_if_running_(HANDLE handle)
{
DWORD exit_code = 0u;
if (handle == INVALID_HANDLE_VALUE)
return ;
if (::GetExitCodeProcess(handle, &exit_code))
if (exit_code == STILL_ACTIVE)
::TerminateProcess(handle, 260);
}
bool check_handle_(HANDLE handle, error_code & ec)
{
if (handle == INVALID_HANDLE_VALUE)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
}
bool check_pid_(pid_type pid_, error_code & ec)
{
if (pid_ == 0)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_INVALID_HANDLE_STATE, system_category())
return false;
}
return true;
}
struct enum_windows_data_t
{
error_code &ec;
pid_type pid;
};
static BOOL CALLBACK enum_window(HWND hwnd, LPARAM param)
{
auto data = reinterpret_cast<enum_windows_data_t*>(param);
DWORD pid{0u};
GetWindowThreadProcessId(hwnd, &pid);
if (pid != data->pid)
return TRUE;
LRESULT res = ::SendMessageW(hwnd, WM_CLOSE, 0, 0);
if (res)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(data->ec)
return res == 0;
}
void request_exit_(pid_type pid_, error_code & ec)
{
enum_windows_data_t data{ec, pid_};
if (!::EnumWindows(enum_window, reinterpret_cast<LONG_PTR>(&data)))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void interrupt_(pid_type pid_, error_code & ec)
{
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::TerminateProcess(handle, 260))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::GetExitCodeProcess(handle, &exit_status))
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#if !defined(BOOST_PROCESS_V2_DISABLE_UNDOCUMENTED_API)
void suspend_(HANDLE handle, error_code & ec)
{
auto nt_err = NtSuspendProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
void resume_(HANDLE handle, error_code & ec)
{
auto nt_err = NtResumeProcess(handle);
ULONG dos_err = RtlNtStatusToDosError(nt_err);
if (dos_err)
BOOST_PROCESS_V2_ASSIGN_LAST_ERROR(ec)
}
#else
void suspend_(HANDLE, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
void resume_(HANDLE handle, error_code & ec)
{
BOOST_PROCESS_V2_ASSIGN_EC(ec, ERROR_CALL_NOT_IMPLEMENTED, system_category())
}
#endif
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
template struct basic_process_handle_win<>;
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_PROCESS_HANDLE_WINDOWS_IPP

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_THROW_ERROR_IPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_THROW_ERROR_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/detail/throw_exception.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
void do_throw_error(const error_code& err)
{
system_error e(err);
throw_exception(e);
}
void do_throw_error(const error_code& err, const char* location)
{
system_error e(err, location);
throw_exception(e);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_THROW_ERROR_IPP

View File

@@ -0,0 +1,379 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_IMPL_UTF8_HPP
#define BOOST_PROCESS_V2_DETAIL_IMPL_UTF8_HPP
#include <boost/process/v2/detail/utf8.hpp>
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/error.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <Windows.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
inline void handle_error(error_code & ec)
{
const auto err = ::GetLastError();
switch (err)
{
case ERROR_INSUFFICIENT_BUFFER:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::utf8_category)
break;
case ERROR_NO_UNICODE_TRANSLATION:
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::utf8_category)
break;
default:
BOOST_PROCESS_V2_ASSIGN_EC(ec, err, system_category())
}
}
std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec)
{
auto res = WideCharToMultiByte(
CP_UTF8, // CodePage,
0, // dwFlags,
in, // lpWideCharStr,
static_cast<int>(size), // cchWideChar,
nullptr, // lpMultiByteStr,
0, // cbMultiByte,
nullptr, // lpDefaultChar,
FALSE); // lpUsedDefaultChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec)
{
auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpMultiByteStr
static_cast<int>(size), // cbMultiByte
nullptr, // lpWideCharStr
0); // cchWideChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t convert_to_utf8(const wchar_t *in, std::size_t size, char * out,
std::size_t max_size, error_code & ec)
{
auto res = ::WideCharToMultiByte(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpWideCharStr
static_cast<int>(size), // cchWideChar
out, // lpMultiByteStr
static_cast<int>(max_size), // cbMultiByte
nullptr, // lpDefaultChar
FALSE); // lpUsedDefaultChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
std::size_t convert_to_wide(const char *in, std::size_t size, wchar_t * out,
std::size_t max_size, error_code & ec)
{
auto res = ::MultiByteToWideChar(
CP_UTF8, // CodePage
0, // dwFlags
in, // lpMultiByteStr
static_cast<int>(size), // cbMultiByte
out, // lpWideCharStr
static_cast<int>(max_size)); // cchWideChar
if (res == 0u)
handle_error(ec);
return static_cast<std::size_t>(res);
}
#else
template<std::size_t s>
inline int get_cont_octet_out_count_impl(wchar_t word) {
if (word < 0x80) {
return 0;
}
if (word < 0x800) {
return 1;
}
return 2;
}
template<>
inline int get_cont_octet_out_count_impl<4>(wchar_t word) {
if (word < 0x80) {
return 0;
}
if (word < 0x800) {
return 1;
}
// Note that the following code will generate warnings on some platforms
// where wchar_t is defined as UCS2. The warnings are superfluous as the
// specialization is never instantiated with such compilers, but this
// can cause problems if warnings are being treated as errors, so we guard
// against that. Including <boost/detail/utf8_codecvt_facet.hpp> as we do
// should be enough to get WCHAR_MAX defined.
#if !defined(WCHAR_MAX)
# error WCHAR_MAX not defined!
#endif
// cope with VC++ 7.1 or earlier having invalid WCHAR_MAX
#if defined(_MSC_VER) && _MSC_VER <= 1310 // 7.1 or earlier
return 2;
#elif WCHAR_MAX > 0x10000
if (word < 0x10000) {
return 2;
}
if (word < 0x200000) {
return 3;
}
if (word < 0x4000000) {
return 4;
}
return 5;
#else
return 2;
#endif
}
inline int get_cont_octet_out_count(wchar_t word)
{
return detail::get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
}
// copied from boost/detail/utf8_codecvt_facet.ipp
// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
inline unsigned int get_octet_count(unsigned char lead_octet)
{
// if the 0-bit (MSB) is 0, then 1 character
if (lead_octet <= 0x7f) return 1;
// Otherwise the count number of consecutive 1 bits starting at MSB
// assert(0xc0 <= lead_octet && lead_octet <= 0xfd);
if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
else return 6;
}
inline bool invalid_continuing_octet(unsigned char octet_1) {
return (octet_1 < 0x80|| 0xbf< octet_1);
}
inline unsigned int get_cont_octet_count(unsigned char lead_octet)
{
return get_octet_count(lead_octet) - 1;
}
inline const wchar_t * get_octet1_modifier_table() noexcept
{
static const wchar_t octet1_modifier_table[] = {
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
};
return octet1_modifier_table;
}
std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec)
{
std::size_t res = 0u;
const auto from_end = in + size;
for (auto from = in; from != from_end; from++)
res += get_cont_octet_out_count(*from) + 1;
return res;
}
std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec)
{
const auto from = in;
const auto from_end = from + size;
const char * from_next = from;
for (std::size_t char_count = 0u; from_next < from_end; ++char_count) {
unsigned int octet_count = get_octet_count(*from_next);
// The buffer may represent incomplete characters, so terminate early if one is found
if (octet_count > static_cast<std::size_t>(from_end - from_next))
break;
from_next += octet_count;
}
return from_next - from;
}
std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
char * out, std::size_t max_size, error_code & ec)
{
const wchar_t * from = in;
const wchar_t * from_end = from + size;
const wchar_t * & from_next = from;
char * to = out;
char * to_end = out + max_size;
char * & to_next = to;
const wchar_t * const octet1_modifier_table = get_octet1_modifier_table();
wchar_t max_wchar = (std::numeric_limits<wchar_t>::max)();
while (from != from_end && to != to_end) {
// Check for invalid UCS-4 character
if (*from > max_wchar) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
int cont_octet_count = get_cont_octet_out_count(*from);
// RG - comment this formula better
int shift_exponent = cont_octet_count * 6;
// Process the first character
*to++ = static_cast<char>(octet1_modifier_table[cont_octet_count] +
(unsigned char)(*from / (1 << shift_exponent)));
// Process the continuation characters
// Invariants: At the start of the loop:
// 1) 'i' continuing octets have been generated
// 2) '*to' points to the next location to place an octet
// 3) shift_exponent is 6 more than needed for the next octet
int i = 0;
while (i != cont_octet_count && to != to_end) {
shift_exponent -= 6;
*to++ = static_cast<char>(0x80 + ((*from / (1 << shift_exponent)) % (1 << 6)));
++i;
}
// If we filled up the out buffer before encoding the character
if (to == to_end && i != cont_octet_count) {
from_next = from;
to_next = to - (i + 1);
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
++from;
}
from_next = from;
to_next = to;
// Were we done or did we run out of destination space
if (from != from_end)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}
inline bool invalid_leading_octet(unsigned char octet_1) {
return (0x7f < octet_1 && octet_1 < 0xc0) ||
(octet_1 > 0xfd);
}
std::size_t convert_to_wide(const char * in, std::size_t size,
wchar_t * out, std::size_t max_size, error_code & ec)
{
const char * from = in;
const char * from_end = from + size;
const char * & from_next = from;
wchar_t * to = out;
wchar_t * to_end = out + max_size;
wchar_t * & to_next = to;
// Basic algorithm: The first octet determines how many
// octets total make up the UCS-4 character. The remaining
// "continuing octets" all begin with "10". To convert, subtract
// the amount that specifies the number of octets from the first
// octet. Subtract 0x80 (1000 0000) from each continuing octet,
// then mash the whole lot together. Note that each continuing
// octet only uses 6 bits as unique values, so only shift by
// multiples of 6 to combine.
const wchar_t * const octet1_modifier_table = detail::get_octet1_modifier_table();
while (from != from_end && to != to_end) {
// Error checking on the first octet
if (invalid_leading_octet(*from)) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
// The first octet is adjusted by a value dependent upon
// the number of "continuing octets" encoding the character
const int cont_octet_count = get_cont_octet_count(*from);
// The unsigned char conversion is necessary in case char is
// signed (I learned this the hard way)
wchar_t ucs_result =
(unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];
// Invariants:
// 1) At the start of the loop, 'i' continuing characters have been
// processed
// 2) *from points to the next continuing character to be processed.
int i = 0;
while (i != cont_octet_count && from != from_end) {
// Error checking on continuing characters
if (invalid_continuing_octet(*from)) {
from_next = from;
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::invalid_character, error::get_utf8_category())
return 0u;
}
ucs_result *= (1 << 6);
// each continuing character has an extra (10xxxxxx)b attached to
// it that must be removed.
ucs_result += (unsigned char)(*from++) - 0x80;
++i;
}
// If the buffer ends with an incomplete unicode character...
if (from == from_end && i != cont_octet_count) {
// rewind "from" to before the current character translation
from_next = from - (i + 1);
to_next = to;
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return 0u;
}
*to++ = ucs_result;
}
from_next = from;
to_next = to;
if (from != from_end)
BOOST_PROCESS_V2_ASSIGN_EC(ec, error::insufficient_buffer, error::get_utf8_category())
return to_next - out;
}
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_UTF8_HPP

View File

@@ -0,0 +1,28 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP
#define BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP
#include <boost/process/v2/detail/config.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
BOOST_PROCESS_V2_DECL error_code get_last_error();
}
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/last_error.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_LAST_ERROR_HPP

View File

@@ -0,0 +1,355 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_HPP
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_HPP
#include <boost/process/v2/detail/config.hpp>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/compose.hpp>
#include <asio/posix/basic_stream_descriptor.hpp>
#include <asio/post.hpp>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/posix/basic_stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_fd
{
using native_handle_type = int;
typedef Executor executor_type;
executor_type get_executor()
{ return descriptor_.get_executor(); }
/// Rebinds the process_handle to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_process_handle_fd<Executor1> other;
};
template<typename ExecutionContext>
basic_process_handle_fd(ExecutionContext &context,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value>::type * = nullptr)
: pid_(-1), descriptor_(context)
{
}
basic_process_handle_fd(executor_type executor)
: pid_(-1), descriptor_(executor)
{
}
basic_process_handle_fd(executor_type executor, pid_type pid)
: pid_(pid), descriptor_(executor, syscall(SYS_pidfd_open, pid, 0))
{
}
basic_process_handle_fd(executor_type executor, pid_type pid, native_handle_type process_handle)
: pid_(pid), descriptor_(executor, process_handle)
{
}
basic_process_handle_fd(basic_process_handle_fd &&handle)
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
{
handle.pid_ = -1;
}
template<typename Executor1>
basic_process_handle_fd(basic_process_handle_fd<Executor1> &&handle)
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
{
handle.pid_ = -1;
}
basic_process_handle_fd& operator=(basic_process_handle_fd &&handle)
{
pid_ = handle.pid_;
descriptor_ = std::move(handle.descriptor_);
handle.pid_ = -1;
return *this;
}
pid_type id() const
{ return pid_; }
native_handle_type native_handle() {return pid_;}
void terminate_if_running(error_code &)
{
if (pid_ <= 0)
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
::waitpid(pid_, nullptr, 0);
}
}
void terminate_if_running()
{
if (pid_ <= 0)
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
::waitpid(pid_, nullptr, 0);
}
}
void wait(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
while (::waitpid(pid_, &exit_status, 0) < 0)
{
if (errno != EINTR)
{
ec = get_last_error();
break;
}
}
}
void wait(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
wait(exit_status, ec);
if (ec)
detail::throw_error(ec, "wait(pid)");
}
void interrupt(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGINT) == -1)
ec = get_last_error();
}
void interrupt()
{
if (pid_ <= 0)
return;
error_code ec;
interrupt(ec);
if (ec)
detail::throw_error(ec, "interrupt");
}
void request_exit(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void request_exit()
{
if (pid_ <= 0)
return;
error_code ec;
request_exit(ec);
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return ;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGSTOP) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return ;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGKILL) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
terminate(exit_status, ec);
if (ec)
detail::throw_error(ec, "terminate");
}
bool running(native_exit_code_type &exit_code, error_code & ec)
{
if (pid_ <= 0)
return false;
int code = 0;
int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1)
ec = get_last_error();
else if (res == 0)
return true;
else
ec.clear();
if (res == 0)
return true;
else
{
exit_code = code;
return false;
}
}
bool running(native_exit_code_type &exit_code)
{
if (pid_ <= 0)
return false;
error_code ec;
bool res = running(exit_code, ec);
if (ec)
detail::throw_error(ec, "is_running");
return res;
}
bool is_open() const
{
return pid_ != -1;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, pid_}, handler, descriptor_);
}
private:
template<typename>
friend
struct basic_process_handle_fd;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
pid_type pid_;
template<typename Self>
void operator()(Self &&self)
{
error_code ec;
native_exit_code_type exit_code{};
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else
{
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1)
ec = get_last_error();
}
if (!ec && (wait_res == 0))
{
descriptor.async_wait(
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read, std::move(self));
return;
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
BOOST_PROCESS_V2_ASIO_NAMESPACE::post(descriptor.get_executor(),
completer{ec, exit_code, std::move(self)});
}
template<typename Self>
void operator()(Self &&self, error_code ec, int = 0)
{
native_exit_code_type exit_code{};
if (!ec)
if (::waitpid(pid_, &exit_code, 0) == -1)
ec = get_last_error();
std::move(self).complete(ec, exit_code);
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP

View File

@@ -0,0 +1,383 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_FD_OR_SIGNAL_HPP
#include <boost/process/v2/detail/config.hpp>
#include <sys/types.h>
#include <sys/wait.h>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/posix/basic_stream_descriptor.hpp>
#include <asio/post.hpp>
#include <asio/windows/signal_set.hpp>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/posix/basic_stream_descriptor.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/signal_set.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_fd_or_signal
{
using native_handle_type = int;
typedef Executor executor_type;
executor_type get_executor()
{ return signal_set_.get_executor(); }
/// Rebinds the process_handle to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_process_handle_fd_or_signal<Executor1> other;
};
template<typename ExecutionContext>
basic_process_handle_fd_or_signal(ExecutionContext &context,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
>::type * = nullptr)
: pid_(-1), descriptor_(context)
{
}
template<typename ExecutionContext>
basic_process_handle_fd_or_signal(ExecutionContext &context,
pid_type pid,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
>::type * = nullptr)
: pid_(pid), descriptor_(context)
{
}
template<typename ExecutionContext>
basic_process_handle_fd_or_signal(ExecutionContext &context,
pid_type pid, native_handle_type process_handle,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
>::type * = nullptr)
: pid_(pid), descriptor_(context, process_handle)
{
}
basic_process_handle_fd_or_signal(Executor executor)
: pid_(-1), descriptor_(executor)
{
}
basic_process_handle_fd_or_signal(Executor executor, pid_type pid)
: pid_(pid), descriptor_(executor)
{
}
basic_process_handle_fd_or_signal(Executor executor, pid_type pid, native_handle_type process_handle)
: pid_(pid), descriptor_(executor, process_handle)
{
}
basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal &&handle)
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
{
handle.pid_ = -1;
}
// Warn: does not change the executor of the signal-set.
basic_process_handle_fd_or_signal& operator=(basic_process_handle_fd_or_signal &&handle)
{
pid_ = handle.pid_;
descriptor_ = std::move(handle.descriptor_);
handle.pid_ = -1;
return *this;
}
template<typename Executor1>
basic_process_handle_fd_or_signal(basic_process_handle_fd_or_signal<Executor1> &&handle)
: pid_(handle.pid_), descriptor_(std::move(handle.descriptor_))
{
handle.pid_ = -1;
}
pid_type id() const
{ return pid_; }
native_handle_type native_handle() {return pid_;}
void terminate_if_running(error_code &)
{
if (pid_ <= 0)
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
::waitpid(pid_, nullptr, 0);
}
}
void terminate_if_running()
{
if (pid_ <= 0)
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
::waitpid(pid_, nullptr, 0);
}
}
void wait(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
while (::waitpid(pid_, &exit_status, 0) < 0)
{
if (errno != EINTR)
{
ec = get_last_error();
break;
}
}
}
void wait(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
wait(exit_status, ec);
if (ec)
detail::throw_error(ec, "wait(pid)");
}
void interrupt(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGINT) == -1)
ec = get_last_error();
}
void interrupt()
{
if (pid_ <= 0)
return;
error_code ec;
interrupt(ec);
if (ec)
detail::throw_error(ec, "interrupt");
}
void request_exit(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void request_exit()
{
if (pid_ <= 0)
return;
error_code ec;
request_exit(ec);
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return ;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGSTOP) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return ;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return ;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGKILL) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
terminate(exit_status, ec);
if (ec)
detail::throw_error(ec, "terminate");
}
bool running(native_exit_code_type &exit_code, error_code & ec)
{
if (pid_ <= 0)
return false;
int code = 0;
int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1)
ec = get_last_error();
else
ec.clear();
if (process_is_running(res))
return true;
else
{
exit_code = code;
return false;
}
}
bool running(native_exit_code_type &exit_code)
{
if (pid_ <= 0)
return false;
error_code ec;
bool res = running(exit_code, ec);
if (ec)
detail::throw_error(ec, "is_running");
return res;
}
bool is_open() const
{
return pid_ != -1;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{descriptor_, signal_set_, pid_}, handler, descriptor_);
}
private:
template<typename>
friend
struct basic_process_handle_fd_or_signal;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_stream_descriptor<Executor> descriptor_;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_{descriptor_.get_executor(), SIGCHLD};
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::basic_descriptor<Executor> &descriptor;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
pid_type pid_;
bool needs_post = true;
template<typename Self>
void operator()(Self &&self, error_code ec = {}, int = 0)
{
native_exit_code_type exit_code{};
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else
{
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1)
ec = get_last_error();
}
if (!ec && (wait_res == 0))
{
needs_post = false;
if (descriptor.is_open())
descriptor.async_wait(
BOOST_PROCESS_V2_ASIO_NAMESPACE::posix::descriptor_base::wait_read,
std::move(self));
else
handle.async_wait(std::move(self));
return;
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor();
completer cpl{ec, exit_code, std::move(self)};
if (needs_post)
BOOST_PROCESS_V2_ASIO_NAMESPACE::post(exec, std::move(cpl));
else
BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, std::move(cpl));
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_HANDLE_FD_OR_SIGNAL_HPP

View File

@@ -0,0 +1,350 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP
#include <boost/process/v2/detail/config.hpp>
#include <sys/types.h>
#include <sys/wait.h>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/compose.hpp>
#include <asio/dispatch.hpp>
#include <asio/post.hpp>
#include <asio/signal_set.hpp>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/signal_set.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_signal
{
struct native_handle_type
{
native_handle_type() = delete;
native_handle_type(const native_handle_type & ) = delete;
~native_handle_type() = default;
};
typedef Executor executor_type;
executor_type get_executor()
{ return signal_set_.get_executor(); }
/// Rebinds the process_handle to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_process_handle_signal<Executor1> other;
};
template<typename ExecutionContext>
basic_process_handle_signal(ExecutionContext &context,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
>::type * = nullptr)
: pid_(-1), signal_set_(context, SIGCHLD)
{
}
basic_process_handle_signal(Executor executor)
: pid_(-1), signal_set_(executor, SIGCHLD)
{
}
basic_process_handle_signal(Executor executor, pid_type pid)
: pid_(pid), signal_set_(executor, SIGCHLD)
{
}
basic_process_handle_signal(basic_process_handle_signal && handle)
: pid_(handle.pid_), signal_set_(handle.signal_set_.get_executor(), SIGCHLD)
{
handle.pid_ = -1;
}
basic_process_handle_signal& operator=(basic_process_handle_signal && handle)
{
pid_ = handle.id();
signal_set_.~basic_signal_set();
using ss = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor>;
new (&signal_set_) ss(handle.get_executor(), SIGCHLD);
handle.pid_ = -1;
return *this;
}
template<typename Executor1>
basic_process_handle_signal(basic_process_handle_signal<Executor1> && handle)
: pid_(handle.pid_), signal_set_(Executor1(handle.signal_set_.get_executor()), SIGCHLD)
{
handle.pid_ = -1;
}
pid_type id() const { return pid_; }
native_handle_type native_handle() {return {};}
void terminate_if_running(error_code &)
{
terminate_if_running();
}
void terminate_if_running()
{
if (pid_ <= 0)
return;
if (::waitpid(pid_, nullptr, WNOHANG) == 0)
{
::kill(pid_, SIGKILL);
::waitpid(pid_, nullptr, 0);
}
}
void wait(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
while (::waitpid(pid_, &exit_status, 0) < 0)
{
if (errno != EINTR)
{
ec = get_last_error();
break;
}
}
}
void wait(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
wait(exit_status, ec);
if (ec)
detail::throw_error(ec, "wait(pid)");
}
void interrupt(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void interrupt()
{
if (pid_ <= 0)
return;
error_code ec;
interrupt(ec);
if (ec)
detail::throw_error(ec, "interrupt");
}
void request_exit(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void request_exit()
{
if (pid_ <= 0)
return;
error_code ec;
request_exit(ec);
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend()
{
if (pid_ <= 0)
return;
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void suspend(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGCONT) == -1)
ec = get_last_error();
}
void resume()
{
if (pid_ <= 0)
return;
error_code ec;
resume(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void resume(error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGTERM) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (pid_ <= 0)
return;
if (::kill(pid_, SIGKILL) == -1)
ec = get_last_error();
}
void terminate(native_exit_code_type &exit_status)
{
if (pid_ <= 0)
return;
error_code ec;
terminate(exit_status, ec);
if (ec)
detail::throw_error(ec, "terminate");
}
bool running(native_exit_code_type &exit_code, error_code & ec)
{
if (pid_ <= 0)
return false;
int code = 0;
int res = ::waitpid(pid_, &code, WNOHANG);
if (res == -1)
ec = get_last_error();
if (res == 0)
return true;
else
{
exit_code = code;
return false;
}
}
bool running(native_exit_code_type &exit_code)
{
if (pid_ <= 0)
return false;
error_code ec;
bool res = running(exit_code, ec);
if (ec)
detail::throw_error(ec, "is_running");
return res;
}
bool is_open() const
{
return pid_ != -1;
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{signal_set_, pid_}, handler, signal_set_);
}
private:
template<typename>
friend struct basic_process_handle_signal;
pid_type pid_ = -1;
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> signal_set_;
struct async_wait_op_
{
BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_signal_set<Executor> &handle;
pid_type pid_;
template<typename Self>
void operator()(Self &&self)
{
handle.async_wait(std::move(self));
handle.cancel();
// we cancel so we end up on the signal-sets executor
}
template<typename Self>
void operator()(Self &&self, error_code ec, int sig)
{
if (ec == BOOST_PROCESS_V2_ASIO_NAMESPACE::error::operation_aborted &&
self.get_cancellation_state().cancelled()
== BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_type::none)
ec.clear();
native_exit_code_type exit_code = -1;
int wait_res = -1;
if (pid_ <= 0) // error, complete early
ec = BOOST_PROCESS_V2_ASIO_NAMESPACE::error::bad_descriptor;
else if (!ec)
{
wait_res = ::waitpid(pid_, &exit_code, WNOHANG);
if (wait_res == -1)
ec = get_last_error();
}
if (!ec && (wait_res == 0))
{
handle.async_wait(std::move(self));
return;
}
struct completer
{
error_code ec;
native_exit_code_type code;
typename std::decay<Self>::type self;
void operator()()
{
self.complete(ec, code);
}
};
const auto exec = self.get_executor();
BOOST_PROCESS_V2_ASIO_NAMESPACE::dispatch(exec, completer{ec, exit_code, std::move(self)});
}
};
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_SIGNAL_HPP

View File

@@ -0,0 +1,305 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
#define BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <boost/process/v2/pid.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/any_io_executor.hpp>
#include <asio/compose.hpp>
#include <asio/windows/basic_object_handle.hpp>
#else
#include <boost/asio/any_io_executor.hpp>
#include <boost/asio/compose.hpp>
#include <boost/asio/windows/basic_object_handle.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
BOOST_PROCESS_V2_DECL void get_exit_code_( void * handle, native_exit_code_type & exit_code, error_code & ec);
BOOST_PROCESS_V2_DECL void * open_process_(pid_type pid);
BOOST_PROCESS_V2_DECL void terminate_if_running_(void * handle);
BOOST_PROCESS_V2_DECL bool check_handle_(void* handle, error_code & ec);
BOOST_PROCESS_V2_DECL bool check_pid_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void interrupt_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void suspend_(void * handle, error_code & ec);
BOOST_PROCESS_V2_DECL void resume_(void * handle, error_code & ec);
BOOST_PROCESS_V2_DECL void terminate_(void * handle, error_code & ec, native_exit_code_type & exit_code);
BOOST_PROCESS_V2_DECL void request_exit_(pid_type pid_, error_code & ec);
BOOST_PROCESS_V2_DECL void check_running_(void* handle, error_code & ec, native_exit_code_type & exit_status);
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_process_handle_win
{
typedef BOOST_PROCESS_V2_ASIO_NAMESPACE::windows::basic_object_handle<Executor> handle_type;
typedef typename handle_type::native_handle_type native_handle_type;
typedef Executor executor_type;
executor_type get_executor()
{ return handle_.get_executor(); }
/// Rebinds the process_handle to another executor.
template<typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_process_handle_win<Executor1> other;
};
template<typename ExecutionContext>
basic_process_handle_win(ExecutionContext &context,
typename std::enable_if<
std::is_convertible<ExecutionContext &,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context &>::value
>::type = 0)
: pid_(0), handle_(context)
{
}
basic_process_handle_win(Executor executor)
: pid_(0), handle_(executor)
{
}
basic_process_handle_win(Executor executor, pid_type pid)
: pid_(pid), handle_(executor, detail::open_process_(pid))
{
}
basic_process_handle_win(Executor executor, pid_type pid, native_handle_type process_handle)
: pid_(pid), handle_(executor, process_handle)
{
}
template<typename Executor1>
basic_process_handle_win(basic_process_handle_win<Executor1> && handle)
: pid_(handle.pid_), handle_(std::move(handle.handle_))
{
}
basic_process_handle_win(basic_process_handle_win && handle)
: pid_(handle.id()), handle_(std::move(handle.handle_))
{
handle.pid_ = static_cast<DWORD>(-1);
}
basic_process_handle_win& operator=(basic_process_handle_win && handle)
{
pid_ = handle.pid_;
handle_ = std::move(handle.handle_);
handle.pid_ = static_cast<DWORD>(-1);
return *this;
}
~basic_process_handle_win()
{
if (handle_.is_open())
{
error_code ec;
handle_.close(ec);
}
}
native_handle_type native_handle()
{ return handle_.native_handle(); }
pid_type id() const
{ return pid_; }
void terminate_if_running(error_code &)
{
detail::terminate_if_running_(handle_.native_handle());
}
void terminate_if_running()
{
detail::terminate_if_running_(handle_.native_handle());
}
void wait(native_exit_code_type &exit_status, error_code &ec)
{
if (!detail::check_handle_(handle_.native_handle(), ec))
return;
handle_.wait(ec);
if (!ec)
detail::get_exit_code_(handle_.native_handle(), exit_status, ec);
}
void wait(native_exit_code_type &exit_status)
{
error_code ec;
wait(exit_status, ec);
if (ec)
detail::throw_error(ec, "wait(pid)");
}
void interrupt(error_code &ec)
{
if (!detail::check_pid_(pid_, ec))
return;
detail::interrupt_(pid_, ec);
}
void interrupt()
{
error_code ec;
interrupt(ec);
if (ec)
detail::throw_error(ec, "interrupt");
}
void request_exit(error_code &ec)
{
if (!detail::check_pid_(pid_, ec))
return;
detail::request_exit_(pid_, ec);
}
void request_exit()
{
error_code ec;
request_exit(ec);
if (ec)
detail::throw_error(ec, "request_exit");
}
void suspend(error_code &ec)
{
detail::suspend_(handle_.native_handle(), ec);
}
void suspend()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "suspend");
}
void resume(error_code &ec)
{
detail::resume_(handle_.native_handle(), ec);
}
void resume()
{
error_code ec;
suspend(ec);
if (ec)
detail::throw_error(ec, "resume");
}
void terminate(native_exit_code_type &exit_status, error_code &ec)
{
if (!detail::check_handle_(handle_.native_handle(), ec))
return;
detail::terminate_(handle_.native_handle(), ec, exit_status);
if (!ec)
wait(exit_status, ec);
}
void terminate(native_exit_code_type &exit_status)
{
error_code ec;
terminate(exit_status, ec);
if (ec)
detail::throw_error(ec, "terminate");
}
bool running(native_exit_code_type &exit_code, error_code & ec)
{
if (!detail::check_handle_(handle_.native_handle(), ec))
return false;
native_exit_code_type code;
//single value, not needed in the winapi.
detail::check_running_(handle_.native_handle(), ec, code);
if (ec)
return false;
if (process_is_running(code))
return true;
else
{
exit_code = code;
return false;
}
}
bool running(native_exit_code_type &exit_code)
{
error_code ec;
bool res = running(exit_code, ec);
if (ec)
detail::throw_error(ec, "is_running");
return res;
}
bool is_open() const
{
return handle_.is_open();
}
template<BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void(error_code, native_exit_code_type))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, native_exit_code_type))
async_wait(WaitHandler &&handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, native_exit_code_type)>(
async_wait_op_{handle_}, handler, handle_
);
}
template<typename>
friend struct basic_process_handle_win;
private:
pid_type pid_;
handle_type handle_;
struct async_wait_op_
{
handle_type &handle;
template<typename Self>
void operator()(Self &&self)
{
handle.async_wait(std::move(self));
}
template<typename Self>
void operator()(Self &&self, error_code ec)
{
native_exit_code_type exit_code{};
if (!ec)
detail::get_exit_code_(handle.native_handle(), exit_code, ec);
std::move(self).complete(ec, exit_code);
}
};
};
#if !defined(BOOST_PROCESS_V2_HEADER_ONLY)
extern template struct basic_process_handle_win<>;
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_PROCESS_HANDLE_WINDOWS_HPP

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP
#define BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP
#include <boost/process/v2/detail/config.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
BOOST_PROCESS_V2_DECL void do_throw_error(const error_code& err);
BOOST_PROCESS_V2_DECL void do_throw_error(const error_code& err, const char* location);
inline void throw_error(const error_code& err)
{
if (err)
do_throw_error(err);
}
inline void throw_error(const error_code& err, const char* location)
{
if (err)
do_throw_error(err, location);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/throw_error.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_THROW_ERROR_HPP

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_THROW_EXCEPTION_HPP
#define BOOST_PROCESS_V2_DETAIL_THROW_EXCEPTION_HPP
#include <boost/process/v2/detail/config.hpp>
#if !defined(BOOST_PROCESS_V2_STANDALONE)
#include <boost/throw_exception.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
#if defined(BOOST_PROCESS_V2_STANDALONE)
template <typename Exception>
inline void throw_exception(const Exception& e)
{
throw e;
}
#else
using boost::throw_exception;
#endif
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_THROW_EXCEPTION_HPP

View File

@@ -0,0 +1,95 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_DETAIL_UTF8_HPP
#define BOOST_PROCESS_V2_DETAIL_UTF8_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
BOOST_PROCESS_V2_DECL std::size_t size_as_utf8(const wchar_t * in, std::size_t size, error_code & ec);
BOOST_PROCESS_V2_DECL std::size_t size_as_wide(const char * in, std::size_t size, error_code & ec);
BOOST_PROCESS_V2_DECL std::size_t convert_to_utf8(const wchar_t * in, std::size_t size,
char * out, std::size_t max_size, error_code & ec);
BOOST_PROCESS_V2_DECL std::size_t convert_to_wide(const char * in, std::size_t size,
wchar_t * out, std::size_t max_size, error_code & ec);
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
typename Allocator = std::allocator<CharOut>, typename CharIn,
typename = typename std::enable_if<std::is_same<CharOut, CharIn>::value>::type>
BOOST_PROCESS_V2_DECL
std::basic_string<CharOut, Traits, Allocator> conv_string(
const CharIn * data, std::size_t size,
const Allocator allocator = Allocator{})
{
return std::basic_string<CharOut, Traits, Allocator>(data, size, allocator);
}
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
typename Allocator = std::allocator<CharOut>,
typename = typename std::enable_if<std::is_same<CharOut, char>::value>::type>
BOOST_PROCESS_V2_DECL
std::basic_string<CharOut, Traits, Allocator> conv_string(
const wchar_t * data, std::size_t size,
const Allocator allocator = Allocator{})
{
error_code ec;
const auto req_size = size_as_utf8(data, size, ec);
if (ec)
detail::throw_error(ec, "size_as_utf8");
std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size);
auto res_size = convert_to_utf8(data, size, &res.front(), req_size, ec);
if (ec)
detail::throw_error(ec, "convert_to_utf8");
res.resize(res_size);
return res;
}
template<typename CharOut, typename Traits = std::char_traits<CharOut>,
typename Allocator = std::allocator<CharOut>,
typename = typename std::enable_if<std::is_same<CharOut, wchar_t>::value>::type>
BOOST_PROCESS_V2_DECL
std::basic_string<CharOut, Traits, Allocator> conv_string(
const char * data, std::size_t size,
const Allocator allocator = Allocator{})
{
error_code ec;
const auto req_size = size_as_wide(data, size, ec);
if (ec)
detail::throw_error(ec, "size_as_wide");
std::basic_string<CharOut, Traits, Allocator> res(allocator);
res.resize(req_size);
auto res_size = convert_to_wide(data, size, &res.front(), req_size, ec);
if (ec)
detail::throw_error(ec, "convert_to_wide");
res.resize(res_size);
return res;
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/detail/impl/utf8.ipp>
#endif
#endif //BOOST_PROCESS_V2_DETAIL_UTF8_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2021 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_ERROR_HPP
#define BOOST_PROCESS_V2_ERROR_HPP
#include <boost/process/v2/detail/config.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace error
{
/// Errors used for utf8 <-> UCS-2 conversions.
enum utf8_conv_error
{
insufficient_buffer = 1,
invalid_character,
};
extern BOOST_PROCESS_V2_DECL const error_category& get_utf8_category();
static const error_category& utf8_category = get_utf8_category();
extern BOOST_PROCESS_V2_DECL const error_category& get_exit_code_category();
/// An error category that can be used to interpret exit codes of subprocesses.
/** Currently not used by boost.process, but it might be in the future.
*
* void run_my_process(filesystem::path pt, error_code & ec)
* {
* process proc(pt, {});
* proc.wait();
* ec.assign(proc.native_exit_code(), error::get_exit_code_category());
* }
*
* */
static const error_category& exit_code_category = get_exit_code_category();
}
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/error.ipp>
#endif
#endif //BOOST_PROCESS_V2_ERROR_HPP

View File

@@ -0,0 +1,120 @@
// Copyright (c) 2022 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_EXECUTE_HPP
#define BOOST_PROCESS_V2_EXECUTE_HPP
#include <boost/process/v2/process.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/bind_cancellation_slot.hpp>
#else
#include <boost/asio/bind_cancellation_slot.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
/**
* @brief Run a process and wait for it to complete.
*
* @tparam Executor The asio executor of the process handle
* @param proc The process to be run.
* @return int The exit code of the process
* @exception system_error An error that might have occurred during the wait.
*/
template<typename Executor>
inline int execute(basic_process<Executor> proc)
{
return proc.wait();
}
/** \overload int execute(const basic_process<Executor> proc) */
template<typename Executor>
inline int execute(basic_process<Executor> proc, error_code & ec)
{
return proc.wait(ec);
}
namespace detail
{
template<typename Executor>
struct execute_op
{
std::unique_ptr<basic_process<Executor>> proc;
struct cancel
{
using cancellation_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_type;
basic_process<Executor> * proc;
cancel(basic_process<Executor> * proc) : proc(proc) {}
void operator()(cancellation_type tp)
{
error_code ign;
if ((tp & cancellation_type::total) != cancellation_type::none)
proc->interrupt(ign);
else if ((tp & cancellation_type::partial) != cancellation_type::none)
proc->request_exit(ign);
else if ((tp & cancellation_type::terminal) != cancellation_type::none)
proc->terminate(ign);
}
};
template<typename Self>
void operator()(Self && self)
{
self.reset_cancellation_state(BOOST_PROCESS_V2_ASIO_NAMESPACE::enable_total_cancellation());
BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_slot s = self.get_cancellation_state().slot();
if (s.is_connected())
s.emplace<cancel>(proc.get());
auto pro_ = proc.get();
pro_->async_wait(
BOOST_PROCESS_V2_ASIO_NAMESPACE::bind_cancellation_slot(
BOOST_PROCESS_V2_ASIO_NAMESPACE::cancellation_slot(),
std::move(self)));
}
template<typename Self>
void operator()(Self && self, error_code ec, int res)
{
self.get_cancellation_state().slot().clear();
self.complete(ec, res);
}
};
}
/// Execute a process asynchronously
/** This function asynchronously for a process to complete.
*
* Cancelling the execution will signal the child process to exit
* with the following interpretations:
*
* - cancellation_type::total -> interrupt
* - cancellation_type::partial -> request_exit
* - cancellation_type::terminal -> terminate
*
* It is to note that `async_execute` will us the lowest selected cancellation
* type. A subprocess might ignore anything not terminal.
*/
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor,
BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(void (error_code, int))
WaitHandler BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (error_code, int))
async_execute(basic_process<Executor> proc,
WaitHandler && handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor))
{
std::unique_ptr<basic_process<Executor>> pro_(new basic_process<Executor>(std::move(proc)));
auto exec = proc.get_executor();
return BOOST_PROCESS_V2_ASIO_NAMESPACE::async_compose<WaitHandler, void(error_code, int)>(
detail::execute_op<Executor>{std::move(pro_)}, handler, exec);
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_EXECUTE_HPP

View File

@@ -0,0 +1,132 @@
//
// process/exit_code.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_EXIT_CODE_HPP
#define BOOST_PROCESS_V2_EXIT_CODE_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/error.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/associator.hpp>
#include <asio/async_result.hpp>
#else
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#endif
#if defined(BOOST_PROCESS_V2_POSIX)
#include <sys/wait.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(GENERATING_DOCUMENTATION)
/// The native exit-code type, usually an integral value
/** The OS may have a value different from `int` to represent
* the exit codes of subprocesses. It might also
* contain additional information.
*/
typedef implementation_defined native_exit_code_type;
/// Check if the native exit code indicates the process is still running
bool process_is_running(native_exit_code_type code);
/// Obtain the portable part of the exit code, i.e. what the subprocess has returned from main.
int evaluate_exit_code(native_exit_code_type code);
#else
#if defined(BOOST_PROCESS_V2_WINDOWS)
typedef unsigned long native_exit_code_type;
namespace detail
{
constexpr native_exit_code_type still_active = 259u;
}
inline bool process_is_running(native_exit_code_type code)
{
return code == detail::still_active;
}
inline int evaluate_exit_code(native_exit_code_type code)
{
return static_cast<int>(code);
}
#else
typedef int native_exit_code_type;
namespace detail
{
constexpr native_exit_code_type still_active = 0x7f;
}
inline bool process_is_running(int code)
{
return !WIFEXITED(code) && !WIFSIGNALED(code);
}
inline int evaluate_exit_code(int code)
{
if (WIFEXITED(code))
return WEXITSTATUS(code);
else if (WIFSIGNALED(code))
return WTERMSIG(code);
else
return code;
}
#endif
#endif
/// @{
/** Helper to subsume an exit-code into an error_code if there's no actual error isn't set.
* @code {.cpp}
* process proc{ctx, "exit", {"1"}};
*
* proc.async_wait(
* asio::deferred(
* [&proc](error_code ec, int)
* {
* return asio::deferred.values(
* check_exit_code(ec, proc.native_exit_code())
* );
*
* [](error_code ec)
* {
* assert(ec.value() == 10);
* assert(ec.category() == error::get_exit_code_category());
* }));
*
* @endcode
*/
inline error_code check_exit_code(
error_code &ec, native_exit_code_type native_code,
const error_category & category = error::get_exit_code_category())
{
if (!ec)
BOOST_PROCESS_V2_ASSIGN_EC(ec, native_code, category);
return ec;
}
/// @}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP

View File

@@ -0,0 +1,16 @@
//
// Copyright (c) 2023 Klemens Morgenstern (klemens.morgenstern@gmx.net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_EXT_HPP
#define BOOST_PROCESS_V2_EXT_HPP
#include <boost/process/v2/ext/cmd.hpp>
#include <boost/process/v2/ext/cwd.hpp>
#include <boost/process/v2/ext/env.hpp>
#include <boost/process/v2/ext/exe.hpp>
#endif //BOOST_PROCESS_V2_EXT_HPP

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2022 Klemens D. Morgenstern
// Copyright (c) 2022 Samuel Venable
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PROCESS_V2_CMD_HPP
#define BOOST_PROCESS_V2_CMD_HPP
#include <string>
#include <vector>
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/throw_error.hpp>
#include <boost/process/v2/process_handle.hpp>
#include <boost/process/v2/pid.hpp>
#include <boost/process/v2/shell.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace ext {
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle, error_code & ec);
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle);
#endif
/// @{
/// Get the argument vector of another process
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid, error_code & ec);
BOOST_PROCESS_V2_DECL shell cmd(pid_type pid);
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle, error_code & ec);
BOOST_PROCESS_V2_DECL shell cmd(HANDLE handle);
#endif
template<typename Executor>
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle, error_code & ec)
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
return cmd(handle.native_handle(), ec);
#else
return cmd(handle.id(), ec);
#endif
}
template<typename Executor>
BOOST_PROCESS_V2_DECL shell cmd(basic_process_handle<Executor> & handle)
{
#if defined(BOOST_PROCESS_V2_WINDOWS)
return cmd(handle.native_handle());
#else
return cmd(handle.id());
#endif
}
/// @}
} // namespace ext
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/ext/impl/cmd.ipp>
#endif
#endif // BOOST_PROCESS_V2_CMD_HPP

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