2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-19 16:32:15 +00:00

Compare commits

...

187 Commits

Author SHA1 Message Date
Klemens
9edacbdb98 ec fix for search_path with std::filesystem.
closes #287.
2023-01-04 08:11:22 +08:00
Klemens Morgenstern
a9f083f45c Update process.cpp 2022-12-13 13:50:03 +08:00
Klemens Morgenstern
b5ab94c932 Disabled some tests for freebsd & added interrupt handling to osx test. 2022-12-13 10:45:47 +08:00
sdarwin
9ceda79fa2 Update metadata 2022-12-13 09:22:13 +08:00
Klemens Morgenstern
68cbeae491 Typo fix. 2022-12-13 09:19:45 +08:00
Klemens Morgenstern
ae778f36a8 Include fixes. 2022-11-11 11:14:46 +08:00
Sam Darwin
0671e4a133 Drone: update freebsd jobs (#274) 2022-11-01 10:40:04 +08:00
Klemens Morgenstern
cbf944c57b using scope-exit limit group_wait. 2022-11-01 03:08:12 +08:00
Klemens Morgenstern
5f2b8c53f4 Disabled limit_fd for freebsd. 2022-11-01 02:58:31 +08:00
Klemens Morgenstern
dac3614a38 group wait test on_scope exit fix. 2022-10-31 12:25:30 +08:00
Klemens Morgenstern
2fc71ca0a3 Disabled pdfork by default, bc of asio errors. 2022-10-31 11:23:49 +08:00
Klemens Morgenstern
404682d75d Increased timeout for sporadically failing test. 2022-10-31 11:21:48 +08:00
Klemens Morgenstern
9fbbdc3421 Merge pull request #276 from Flamefire/patch-1
Update .drone.star
2022-10-23 11:21:09 +08:00
Alexander Grund
3df0009a2f 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-10-22 11:26:04 +02:00
Klemens Morgenstern
ecb384b253 Improved error message for OSX. 2022-10-21 12:03:31 +08:00
Klemens Morgenstern
05bce942c1 passing a pipe into sh test. 2022-10-12 11:54:05 +08:00
Klemens Morgenstern
dcf5d8ce41 Added return_type to async_result<code_as_error_t> 2022-10-12 10:54:30 +08:00
Klemens Morgenstern
4209f8ee6e Minor bugfixes 2022-10-12 01:12:28 +08:00
Klemens Morgenstern
d9513269cc Enabled freebsd build 2022-10-11 21:03:33 +08:00
Klemens
293f28dab6 Fixed async_system. 2022-09-20 13:45:43 +08:00
Klemens
fe1b629b5d Added bind_launcher. 2022-09-18 22:13:57 +08:00
Klemens
278fa57214 Added code_as_error completion handler. 2022-09-18 17:56:47 +08:00
Klemens Morgenstern
1addfba12e Added WIN32_LEAN_AND_MEAN to cmake 2022-09-17 20:39:01 +08:00
Klemens Morgenstern
4cc469b2a4 Merge pull request #252 from grtowel1510f/patch-1
fix issue #251 - fix simple shell command in posix
2022-09-14 11:38:37 +08:00
Klemens Morgenstern
6e4d1e29d2 Merge pull request #271 from boostorg/shell_v2
Shell v2
2022-09-02 20:30:03 +08:00
Klemens Morgenstern
dada865fd0 Merge pull request #269 from boostorg/klemens-morgenstern-patch-2
Closes #266
2022-09-02 20:29:20 +08:00
Klemens Morgenstern
380dd1b00f Merge pull request #268 from boostorg/klemens-morgenstern-patch-1
Closes #267
2022-09-02 20:28:50 +08:00
Klemens
7832cb6af3 Shell(posix) fixes. 2022-09-02 18:43:35 +08:00
Klemens Morgenstern
68f4c50be9 Exeuction support for shell. 2022-09-02 18:25:40 +08:00
Klemens Morgenstern
cd226a7616 Implemented shell on windows. 2022-09-02 17:05:49 +08:00
Klemens Morgenstern
4243ce72f8 Windows bugfixes. 2022-09-02 16:46:45 +08:00
Klemens
9065833e61 Added shell class. 2022-08-31 23:54:22 +08:00
Klemens Morgenstern
7cb7af6c8b Closes #267 2022-08-31 15:40:57 +08:00
Klemens Morgenstern
90cbe7cec0 Closes #266 2022-08-31 15:35:51 +08:00
Klemens
df33c1ad7b Fixed unsafe post-fork allocs for fd_whitelist. 2022-08-31 15:35:41 +08:00
Klemens
bbabea30dd Added reaping child for execve error, closes #265. 2022-08-31 15:35:41 +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
grtowel1510f
8a61f8daa3 fix issue #251 - fix simple shell command in posix
see issue #251 for description.
2022-05-21 14:59:37 +00: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
c1d0f1be76 Merge pull request #227 from x-santiaga-x/patch-1
Closes klemens-morgenstern/boost-process#218
2021-10-29 18:59:23 +08:00
Klemens Morgenstern
10c93d88a1 Merge pull request #228 from x-santiaga-x/patch-2
Fix missing headers
2021-10-29 18:55:03 +08:00
silent
5f80e72e9c Closes klemens-morgenstern/boost-process#218 2021-10-29 13:24:19 +03:00
silent
d26ef52519 fix missing headers 2021-10-29 12:18:20 +03:00
Klemens Morgenstern
f4d2c260d4 Merge pull request #231 from klemens-morgenstern/develop
Master update
2021-10-27 17:36:17 +08:00
Klemens Morgenstern
e32651a260 Removed overly constraint tests. 2021-10-27 12:23:18 +08:00
Klemens Morgenstern
71aa7d9c00 Merge commit 'ed3b066' into develop 2021-10-27 11:45:43 +08:00
Klemens Morgenstern
ed3b066da1 Multiple windows test fixes 2021-10-27 11:43:33 +08:00
Klemens
83380dad79 Increased log level on windows. 2021-10-26 23:53:02 +08:00
Klemens
5ad5e82577 Trying to catch windows early complete. 2021-10-22 19:42:53 +08:00
Klemens
3acc1a3fa8 Added missing work guard on windows. 2021-10-16 15:46:11 +08:00
Klemens
9bb088ed5d Closes boostorg/process#191. 2021-10-15 10:57:01 +08:00
Klemens
cd4ef692e1 Closes boostorg/process#189. 2021-10-15 10:54:38 +08:00
Klemens
268795f3c0 Multiple fixes. 2021-10-14 17:41:27 +08:00
Klemens
f8f9c2323c Changed child(pid_t) signature. 2021-10-14 15:36:07 +08:00
Klemens
0c3ded6636 Closes boostorg/process#197. 2021-10-14 15:36:07 +08:00
Klemens
20b328dbf1 Attempting to fix wchar_t build error on circle. 2021-10-14 14:48:23 +08:00
Klemens
a60203dac3 Closes boostorg/process#121 2021-10-14 14:48:23 +08:00
Klemens
6d08cb369e Closes boostorg/process#190 2021-10-14 14:28:07 +08:00
Klemens
8dc5ee22f5 Merge remote-tracking branch 'boostorg/develop' into develop 2021-10-14 14:20:27 +08: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
Klemens
a13a60d428 Removed unneeded WNOHANG. 2021-10-14 14:19:32 +08:00
Klemens Morgenstern
fa2a522ef2 Merge pull request #220 from odhinnsrunes/file_descriptor_move_assign_fix
Fixed file_descriptor move assignment operator returns a reference to this.
2021-10-14 14:14:23 +08:00
Klemens Morgenstern
2b39b56efb Merge pull request #208 from jorj1988/extend_hpp_include_memory
Add include to extend.hpp for memory.
2021-10-09 16:23:38 +08:00
Klemens Morgenstern
5a283e5200 Merge pull request #218 from Val-test/develop
Fix child construction from pid_t (it takes reference to pid_t for no reason).
2021-10-09 16:23:26 +08:00
Klemens Morgenstern
3d5f449052 Merge pull request #223 from apolukhin/patch-1
Remove trailing whitespace
2021-10-09 16:22:13 +08:00
Antony Polukhin
aefb990a7a Remove triling whitespace 2021-10-03 10:30:10 +03:00
Valentyn Pavliuchenko
3d092498b2 Fix child construction from pid_t (it takes reference to pid_t for no reason). 2021-08-19 19:54:42 +03:00
Klemens Morgenstern
7d7476343a Merge pull request #215 from Eddie-cz/develop
Missing include added
2021-08-08 20:09:20 +08:00
Eddie-cz
e08374ed95 Update wchar_t.hpp 2021-08-02 10:49:42 +02:00
Klemens Morgenstern
155ebdcf1f Merge pull request #181 from orgads/patch-1
Fix cross-compile linux->mingw
2021-07-05 14:48:01 +08:00
Orgad Shaneh
a9925a5d6d Fix cross-compile linux->mingw
Headers are lower case.
2021-07-05 09:17:16 +03:00
Peter Dimov
741d3f4a07 Add CMakeLists.txt 2021-05-28 02:42:50 +03:00
Peter Dimov
f195243a81 Merge branch 'master' into develop 2021-05-28 02:40:12 +03:00
George Pimm
8c5ab02192 Add include to extend.hpp for memory.
extend.hpp uses std::shared_ptr as a member but does not include it
2021-04-14 13:52:46 +01:00
Shauren
b526ac7ce5 Fix posix implementation of move constructor/assignment in file_descriptor 2021-01-16 17:02:41 +01:00
Klemens Morgenstern
8222a57744 Merge pull request #192 from eldiener/develop
Add "cxxstd" json field. The "cxxstd" json field is being added to ea…
2020-12-17 17:35:23 +08:00
Edward Diener
aa3ae06ab7 Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries whose minumum C++ standard compilation level is C++11 on up. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. 2020-12-16 10:32:08 -05:00
Klemens Morgenstern
1b4d67170f Merge pull request #177 from giomasce-throwaway/develop
Fix typo in copyright headers.
2020-10-29 21:17:53 +04:00
Klemens Morgenstern
e3594034eb Merge pull request #179 from nre-ableton/nre/develop/posix-default-locale
Return default locale on POSIX systems
2020-10-29 21:17:34 +04:00
Klemens Morgenstern
ee983eba64 Merge pull request #171 from Shauren/fix-windows-h
Fix windows builds that don't include Windows.h
2020-10-29 21:17:05 +04:00
nre
0eb4685558 Return default locale on POSIX systems
The comment here is incorrect; an empty locale is not the correct
behavior here and will cause exceptions to be thrown in other code.
Instead a locale object with the default constructor should be
returned, not one created with an empty string. This is a known issue
which was originally reported here:

https://svn.boost.org/trac10/ticket/4688

The issue claims to have been fixed in 7bb19f9 (see also:
https://svn.boost.org/trac10/changeset/72855).

However, this only fixes the issue for FreeBSD and not other POSIX
platforms. This patch is based on the one originally submitted here:

https://svn.boost.org/trac10/attachment/ticket/4688/boost_filesystem.patch
2020-10-16 10:07:14 +02:00
Giovanni Mascellani
7cf1a3b8e6 Fix typo in copyright headers. 2020-10-09 15:49:45 +02:00
Klemens Morgenstern
c0a1a82361 Merge pull request #173 from alloutlife/issue_121
Adding bug fix to resolve issue #121
2020-09-22 01:46:03 +03:00
Alexey Kushnarev
532951902f Adding bug fix to resolve issue #121 2020-09-14 12:16:14 +03:00
Shauren
642c2d369f Use ::boost::winapi::DWORD_ instead of global DWORD 2020-09-03 13:21:36 +02:00
Shauren
d7a721ee0d Removed __kernel_entry usage from Nt* function typedefs, is is part of SAL annoations, not neccessary for proper signature 2020-09-03 13:21:02 +02:00
James Baker
baa8d3fe7c Returning *this instead of erroneous *this. Issue # 219 2020-08-28 12:43:16 -04:00
James Baker
42bdfb5545 Fixed file_descriptor move assignment operator to return a reference to 'this'. Issue # 219 2020-08-28 11:13:39 -04:00
Klemens Morgenstern
0f053c323e Merge pull request #167 from zaucy/move_assignment_return_value_fix
Added return *this in move assignment operator
2020-08-03 16:29:09 +07:00
Ezekiel Warren
036c9fc4d1 Added return *this in move assignment operator 2020-08-01 18:53:20 -07:00
164 changed files with 13043 additions and 235 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 mlocate", 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 mlocate",
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 mlocate", 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++", packages="mlocate", 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 mlocate", llvm_os="precise", llvm_ver="3.8", image="cppalliance/droneubuntu1604:1", buildtype="boost", buildscript="drone", environment={"VARIANT": "process_ubasan", "TOOLSET": "clang", "COMPILER": "clang++-3.8", "CXXSTD": "11", "UBSAN_OPTIONS": 'print_stacktrace=1', "DRONE_BEFORE_INSTALL": "UBasan" }, globalenv=globalenv),
linux_cxx("gcc 6", "g++-6", packages="g++-6", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'B2_TOOLSET': 'gcc-6', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '902ba3cda1'}, globalenv=globalenv),
linux_cxx("clang 3.8", "clang++-3.8", packages="clang-3.8", buildtype="boost", buildscript="drone", image="cppalliance/droneubuntu1604:1", environment={'B2_TOOLSET': 'clang', 'COMPILER': 'clang++-3.8', 'B2_CXXSTD': '11', 'DRONE_JOB_UUID': '7b52009b64'}, globalenv=globalenv),
osx_cxx("clang", "g++", packages="", buildtype="boost", buildscript="drone", environment={'B2_TOOLSET': 'clang', 'B2_CXXSTD': '11,17', 'DRONE_JOB_UUID': '91032ad7bb'}, globalenv=globalenv),
linux_cxx("coverity", "g++", packages="", buildtype="coverity", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'Coverity Scan', 'B2_TOOLSET': 'clang', 'DRONE_JOB_UUID': '472b07b9fc'}, globalenv=globalenv),
windows_cxx("msvc-14.1", "", image="cppalliance/dronevs2017", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.1", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
windows_cxx("msvc-14.3", "", image="cppalliance/dronevs2022:1", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "msvc-14.3", "CXXSTD": "11", "DEFINE" : "BOOST_BEAST_USE_STD_STRING_VIEW", "ADDRESS_MODEL": "64"}),
]
# from https://github.com/boostorg/boost-ci
load("@boost_ci//ci/drone/:functions.star", "linux_cxx","windows_cxx","osx_cxx","freebsd_cxx")

36
.drone/drone.bat Executable file
View File

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

199
.drone/drone.sh Executable file
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

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

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

36
CMakeLists.txt Normal file
View File

@@ -0,0 +1,36 @@
# Generated by `boostdep --cmake process`
# Copyright 2020 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
cmake_minimum_required(VERSION 3.5...3.16)
project(boost_process VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
add_library(boost_process INTERFACE)
add_library(Boost::process ALIAS boost_process)
target_include_directories(boost_process INTERFACE include)
target_link_libraries(boost_process
INTERFACE
Boost::algorithm
Boost::asio
Boost::config
Boost::core
Boost::filesystem
Boost::fusion
Boost::iterator
Boost::move
Boost::optional
Boost::system
Boost::tokenizer
Boost::type_index
Boost::winapi
)
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
add_subdirectory(test)
endif()

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

@@ -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");
```

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 recommented to use the environment types,
as to have the right value comparisons.
To note is the `find_executable` functions, which searches in an environment for an executable.
```
// search in the current environment
auto exe = environment::find_executable("g++");
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
};
auto other_exe = environment::find_executable("g++", my_env);
```
[section:process_env Subprocess environment]
The subprocess environment assignment follows the same constraints:
```
asio::io_context ctx;
std::unordered_map<environment::key, environment::value> my_env =
{
{"SECRET", "THIS_IS_A_TEST"}
{"PATH", {"/bin", "/usr/bin"}
};
auto exe = find_executable("g++"), my_env);
process proc(ctx, exe, {"main.cpp"}, process_environment(my_env));
process pro2(ctx, exe, {"test.cpp"}, process_environment(my_env));
```
[endsect]
[endsect]

94
doc/v2/introduction.qbk Normal file
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 adresses one logical compoent (e.g. stdio) instead of multiple ones accumulating.
Furthermore, every process has a path and arguments, instead of a confusing mixture of cmd-style and
exe-args that can be randomly spread out.
[endsect]
[section:pidfd_open pidfd_open]
Since process v1 came out, linux has moved along and added pidfd_open which allows users to get a
file descriptor for a process. This is much more reliable since it is not as easy to miss as a `SIGCHLD`.
FreeBSD has a similar feature with `pdfork` which is also supported, while windows has provided `HANDLE`s
for processes all along.
Unless the OS doesn't support it, process v2 will use file descriptors and handles to implement waiting
for processes.
[endsect]
[section:asio Full asio integration]
Process v1 aimed to make asio optional, but synchronous IO with subprocesses usually means one is begging
for deadlocks.
Since asio added pipes in boost 1.78, boost process V2 is fully asio based and uses it's pipes and
file-handles for the subprocess.
[endsect]
[section:unreliable Unreliable functionality]
Certain parts of boost.process were not as reliable as they should've been.
This concerns especially the `wait_for`` and `wait_until` functions on the process.
The latter are easy to do on windows, but posix does not provide an API for this.
Thus the wait_for used signals or fork, which was all but safe.
Since process v2 is based on asio and thus supports cancellation,
a wait_for can not safely be implemented with an async_wait + timeout.
[endsect]
[section:utf8 UTF-8]
["UTF-8 or GTFO]--Vinnie Falco
Instead of using ascii-APIs on windows, process V2 just assumes UTF-8 everywhere.
[endsect]
[section:src Separate compilation]
Boost.process v2 supports separate compilation similar to other boost libraries.
It can be achieved by defining `BOOST_PROCESS_V2_SEPARATE_COMPILATION` and including
`<process/v2/src.hpp>` in a single compile unit.
[endsect]
[section:limit_fd Fd safe by default]
While not a problem on windows (since HANDLEs get manually enabled for inheritance),
posix systems create a problem with inheriting file handles by default.
Process V2 will automatically close all non-whitelisted descriptors,
without needing any option to enable it.
[endsect]
[endsect]

128
doc/v2/launcher.qbk Normal file
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::eror_code ec;
auto proc = l(ctx, ec, "C:\\User\\boost\\Downloads\\totally_not_a_virus.exe", {});
```
The launcher will call certain functions on the initializer if they're present, as documented below.
The initializer are used to modify the process behaviour.
[section:linux Linux Launchers]
The default and pdfork launchers on linux open an internal pipe to communicate errors that occur after forking back to the parent process.
This can be prevented by using the `fork_and_forget_launcher`.
Alternatively, the `vfork_launcher` can report errors directly back to the parent process.
Thus some calls to the initializers occur after forking from the child process.
```
struct custom_initalizer
{
// functions called from the parent process:
// called before a call to fork. A returned error will cancel the launch.
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called after successful process creation
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called for every initializer if an error occured when forking, in addtion to on_error.
template<typename Launcher>
void on_fork_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line),
const error_code & ec);
// called before a call to execve. A returned error will cancel the launch. Called from the child process.
template<typename Launcher>
error_code on_exec_setup(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
// called after a failed call to execve from the child process.
template<typename Launcher>
void on_exec_error(Launcher & launcher, const filesystem::path &executable, const char * const * (&cmd_line));
};
```
The call sequence on success:
'''
<imagedata fileref="boost_process/posix_success.svg"/>
'''
The call sequence when fork fails:
'''
<imagedata fileref="boost_process/posix_fork_err.svg"/>
'''
The call sequence when exec fails:
'''
<imagedata fileref="boost_process/posix_exec_err.svg"/>
'''
The launcher will close all non-whitelisted file descriptors after `on_exec_setup`.
[endsect]
[section:windows Windows Launchers]
Windows launchers are pretty streight forward, they will call the following functions on the initializer if present.
```
struct custom_initializer
{
// called before a call to CreateProcess. A returned error will cancel the launch.
template<typename Launcher>
error_code on_setup(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
// called for every initializer if an error occured during setup or process creation
template<typename Launcher>
void on_error(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line,
const error_code & ec);
// called after successful process creation
template<typename Launcher>
void on_success(Launcher & launcher, const filesystem::path &executable, std::wstring &cmd_line);
};
```
[note All the additional launchers for windows inherit `default_launcher`]
The call sequence is as follows:
'''
<imagedata fileref="boost_process/windows_exec.svg"/>
'''
[endsect]
[endsect]

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

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

16
doc/v2/start_dir.qbk Normal file
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

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

View File

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

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

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

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

@@ -60,7 +60,7 @@ public:
explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {}
explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {}
explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {};
explicit child(pid_t pid) : _child_handle(pid), _attached(false) {};
child(const child&) = delete;
child(child && lhs) noexcept
: _child_handle(std::move(lhs._child_handle)),

View File

@@ -25,6 +25,11 @@ public:
typedef ::boost::asio::posix::stream_descriptor handle_type;
typedef typename handle_type::executor_type executor_type;
executor_type get_executor()
{
return _source.get_executor();
}
inline async_pipe(boost::asio::io_context & ios) : async_pipe(ios, ios) {}
inline async_pipe(boost::asio::io_context & ios_source,
@@ -45,8 +50,8 @@ public:
inline async_pipe(const async_pipe& lhs);
async_pipe(async_pipe&& lhs) : _source(std::move(lhs._source)), _sink(std::move(lhs._sink))
{
lhs._source.assign (-1);
lhs._sink .assign (-1);
lhs._source = ::boost::asio::posix::stream_descriptor{lhs._source.get_executor()};
lhs._sink = ::boost::asio::posix::stream_descriptor{lhs._sink. get_executor()};
}
template<class CharT, class Traits = std::char_traits<CharT>>

View File

@@ -139,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
}
static exe_cmd_init cmd_shell(std::string&& cmd)
{
std::vector<std::string> args = {"-c", "\"" + cmd + "\""};
std::vector<std::string> args = {"-c", cmd};
std::string sh = shell().string();
return exe_cmd_init(

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>
@@ -95,7 +95,7 @@ public:
int_type read(char_type * data, int_type count)
{
int_type read_len;
while ((read_len = ::read(_source, data, count * sizeof(char_type))) == -1)
while ((read_len = static_cast<int_type>(::read(_source, data, count * sizeof(char_type)))) == -1)
{
//Try again if interrupted
auto err = errno;

View File

@@ -56,6 +56,7 @@ public:
{
_buffer = _load();
_impl = _load_var(_buffer);
_env_impl = _impl.data();
}
string_type get(const pointer_type id) { return get(string_type(id)); }

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,15 +151,15 @@ class executor
int _pipe_sink = -1;
void write_error(const std::error_code & ec, const char * msg)
{
//I am the child
int len = ec.value();
::write(_pipe_sink, &len, sizeof(int));
const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), len + 1};
len = std::strlen(msg) + 1;
::write(_pipe_sink, &len, sizeof(int));
::write(_pipe_sink, msg, len);
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::write(_pipe_sink, msg, len));
}
void internal_error_handle(const std::error_code &ec, const char* msg, boost::mpl::true_ , boost::mpl::false_, boost::mpl::false_)
@@ -273,14 +275,15 @@ class executor
prepare_cmd_style_fn = exe;
if ((prepare_cmd_style_fn.find('/') == std::string::npos) && ::access(prepare_cmd_style_fn.c_str(), X_OK))
{
auto e = ::environ;
const auto * e = ::environ;
while ((e != nullptr) && (*e != nullptr) && !boost::starts_with(*e, "PATH="))
e++;
if ((e != nullptr) && (*e != nullptr))
{
std::vector<std::string> path;
boost::split(path, *e, boost::is_any_of(":"));
//the beginning of the string contains "PATH="
boost::split(path, (*e) + 5, boost::is_any_of(":"));
for (const std::string & pp : path)
{
@@ -325,6 +328,13 @@ public:
}
void set_error(const std::error_code &ec, const std::string &msg) {set_error(ec, msg.c_str());};
std::vector<int> get_used_handles() const
{
if (_pipe_sink == -1)
return {};
else
return {_pipe_sink};
};
};
template<typename Sequence>
@@ -434,6 +444,8 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::false_)
}
if (_ec)
{
//if an error occured we need to reap the child process
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}
@@ -527,6 +539,7 @@ child executor<Sequence>::invoke(boost::mpl::false_, boost::mpl::true_)
if (_ec)
{
::waitpid(this->pid, nullptr, WNOHANG);
boost::fusion::for_each(seq, call_on_error(*this, _ec));
return child();
}

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

@@ -42,7 +42,7 @@ struct group_handle
}
void add(handle_t proc)
{
{
if (::setpgid(proc, grp))
throw_last_error();
}

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

@@ -1,4 +1,4 @@
// Copyright (c) 2106 Klemens D. Morgenstern
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

View File

@@ -6,26 +6,39 @@
#ifndef BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#define BOOST_PROCESS_POSIX_ON_EXIT_HPP_
#include <boost/asio/execution.hpp>
#include <boost/process/async.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/posix/async_handler.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace posix {
namespace boost { namespace process { namespace detail {
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup);
namespace posix {
struct on_exit_ : boost::process::detail::posix::async_handler
{
std::function<void(int, const std::error_code&)> handler;
on_exit_(const std::function<void(int, const std::error_code&)> & handler) : handler(handler)
{
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
{
return handler;
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
boost::asio::execution::outstanding_work.tracked);
auto handler_ = this->handler;
return
[handler_, v](int exit_code, const std::error_code & ec)
{
handler_(exit_code, ec);
};
}
};

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

@@ -48,9 +48,22 @@ public:
int status;
auto pid_res = ::waitpid(pid, &status, WNOHANG);
if (pid_res < 0)
h(-1, get_last_error());
{
auto ec = get_last_error();
boost::asio::post(
_strand,
[pid_res, ec, h]
{
h(pid_res, ec);
});
}
else if ((pid_res == pid) && (WIFEXITED(status) || WIFSIGNALED(status)))
h(status, {}); //successfully exited already
boost::asio::post(
_strand,
[status, h]
{
h(status, {}); //successfully exited already
});
else //still running
{
if (_receivers.empty())

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

@@ -27,7 +27,7 @@ inline void terminate(const child_handle &p, std::error_code &ec) noexcept
ec.clear();
int status;
::waitpid(p.pid, &status, WNOHANG); //just to clean it up
::waitpid(p.pid, &status, 0); //should not be WNOHANG, since that would allow zombies.
}
inline void terminate(const child_handle &p)

View File

@@ -158,7 +158,7 @@ inline bool wait_until(
{
int res;
::kill(pid, SIGKILL);
::waitpid(pid, &res, WNOHANG);
::waitpid(pid, &res, 0);
}
};
child_cleaner_t child_cleaner{timeout_pid};

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

@@ -7,6 +7,8 @@
#ifndef BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
#define BOOST_PROCESS_DETAIL_TRAITS_WCHAR_T_HPP_
#include <algorithm>
#include <boost/process/detail/traits/decl.hpp>
#include <boost/process/detail/traits/cmd_or_exe.hpp>
#include <boost/process/detail/traits/env.hpp>
@@ -18,7 +20,7 @@ namespace boost { namespace process { namespace detail {
template<typename T> struct is_wchar_t : std::false_type {};
template<> struct is_wchar_t<boost::filesystem::path> : std::is_same<typename boost::filesystem::path::value_type, wchar_t>
template<> struct is_wchar_t<boost::process::filesystem::path> : std::is_same<typename boost::process::filesystem::path::value_type, wchar_t>
{
};

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

@@ -159,8 +159,13 @@ struct exe_cmd_init : handler_base_ext
return exe_cmd_init<Char>(std::move(sh), std::move(args_));
}
#ifdef BOOST_PROCESS_USE_STD_FS
static std:: string get_shell(char) {return shell(). string(); }
static std::wstring get_shell(wchar_t) {return shell().wstring(); }
#else
static std:: string get_shell(char) {return shell(). string(codecvt()); }
static std::wstring get_shell(wchar_t) {return shell().wstring(codecvt());}
#endif
static exe_cmd_init<Char> cmd_shell(string_type&& cmd)
{

View File

@@ -232,6 +232,8 @@ basic_environment_impl<Char>::basic_environment_impl(const native_environment_im
template<typename Char>
inline auto basic_environment_impl<Char>::get(const string_type &id) -> string_type
{
if (id.size() >= _data.size()) //ok, so it's impossible id is in there.
return string_type(_data.data());
if (std::equal(id.begin(), id.end(), _data.begin()) && (_data[id.size()] == equal_sign<Char>()))
return string_type(_data.data()); //null-char is handled by the string.

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)
{
}
@@ -102,6 +102,7 @@ struct file_descriptor
if (_handle != ::boost::winapi::INVALID_HANDLE_VALUE_)
::boost::winapi::CloseHandle(_handle);
_handle = boost::exchange(other._handle, ::boost::winapi::INVALID_HANDLE_VALUE_);
return *this;
}
~file_descriptor()

View File

@@ -12,7 +12,7 @@
//#define BOOST_USE_WINDOWS_H 1
#if defined( BOOST_USE_WINDOWS_H )
#include <Winternl.h>
#include <winternl.h>
#endif
@@ -198,20 +198,20 @@ typedef struct _OBJECT_TYPE_INFORMATION_ {
/*
__kernel_entry NTSTATUS NtQuerySystemInformation(
NTSTATUS NtQuerySystemInformation(
IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength
);
*/
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_system_query_information_p )(
typedef ::boost::winapi::NTSTATUS_ (*nt_system_query_information_p )(
SYSTEM_INFORMATION_CLASS_,
void *,
::boost::winapi::ULONG_,
::boost::winapi::PULONG_);
/*
__kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
NTSYSCALLAPI NTSTATUS NtQueryObject(
HANDLE Handle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
@@ -220,7 +220,7 @@ __kernel_entry NTSYSCALLAPI NTSTATUS NtQueryObject(
);
*/
typedef ::boost::winapi::NTSTATUS_ (__kernel_entry *nt_query_object_p )(
typedef ::boost::winapi::NTSTATUS_ (*nt_query_object_p )(
::boost::winapi::HANDLE_,
OBJECT_INFORMATION_CLASS_,
void *,

View File

@@ -11,6 +11,7 @@
#include <boost/process/detail/windows/handle_workaround.hpp>
#include <boost/process/detail/windows/handler.hpp>
#include <boost/winapi/get_current_process_id.hpp>
#include <boost/winapi/handles.hpp>
namespace boost { namespace process { namespace detail {
@@ -136,7 +137,7 @@ struct limit_handles_ : handler_base_ext
[&](::boost::winapi::HANDLE_ handle)
{
auto itr = std::find(all_handles.begin(), all_handles .end(), handle);
DWORD flags = 0u;
::boost::winapi::DWORD_ flags = 0u;
if (itr != all_handles.end())
*itr = ::boost::winapi::INVALID_HANDLE_VALUE_;
else if ((::boost::winapi::GetHandleInformation(*itr, &flags) != 0)

View File

@@ -8,7 +8,9 @@
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/process/detail/windows/is_running.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/windows/object_handle.hpp>
#include <boost/winapi/process.hpp>
#include <boost/winapi/handles.hpp>
@@ -114,6 +116,15 @@ struct io_context_ref : boost::process::detail::handler_base
wait_handler wh(std::move(funcs), ios, process_handle, exec.exit_status);
::boost::winapi::DWORD_ code;
if(::boost::winapi::GetExitCodeProcess(process_handle, &code)
&& code != still_active)
{
::boost::asio::post(wh.handle->get_executor(), std::move(wh));
return;
}
auto handle_p = wh.handle.get();
handle_p->async_wait(std::move(wh));
}
@@ -130,12 +141,13 @@ struct io_context_ref : boost::process::detail::handler_base
boost::asio::io_context & ios, void * handle,
const std::shared_ptr<std::atomic<int>> &exit_status)
: funcs(std::move(funcs)),
handle(new boost::asio::windows::object_handle(ios.get_executor(), handle)),
handle(new boost::asio::windows::object_handle(
asio::prefer(ios.get_executor(), asio::execution::outstanding_work.tracked), handle)),
exit_status(exit_status)
{
}
void operator()(const boost::system::error_code & ec_in)
void operator()(const boost::system::error_code & ec_in = {})
{
std::error_code ec;
if (ec_in)

View File

@@ -1,4 +1,4 @@
// Copyright (c) 2106 Klemens D. Morgenstern
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -7,6 +7,7 @@
#define BOOST_PROCESS_WINDOWS_IS_RUNNING_HPP
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/windows/child_handle.hpp>
#include <system_error>
#include <cstdlib>
#include <boost/winapi/process.hpp>

View File

@@ -6,13 +6,20 @@
#ifndef BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#define BOOST_PROCESS_WINDOWS_ON_EXIT_HPP_
#include <boost/process/async.hpp>
#include <boost/process/detail/config.hpp>
#include <boost/process/detail/handler_base.hpp>
#include <boost/process/detail/windows/async_handler.hpp>
#include <boost/asio/execution.hpp>
#include <system_error>
#include <functional>
namespace boost { namespace process { namespace detail { namespace windows {
namespace boost { namespace process { namespace detail {
template<typename Tuple>
inline asio::io_context& get_io_context(const Tuple & tup);
namespace windows {
struct on_exit_ : boost::process::detail::windows::async_handler
{
@@ -23,10 +30,12 @@ struct on_exit_ : boost::process::detail::windows::async_handler
}
template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
std::function<void(int, const std::error_code&)> on_exit_handler(Executor& exec)
{
auto v = boost::asio::prefer(boost::process::detail::get_io_context(exec.seq).get_executor(),
boost::asio::execution::outstanding_work.tracked);
auto handler_ = this->handler;
return [handler_](int exit_code, const std::error_code & ec)
return [v, handler_](int exit_code, const std::error_code & ec)
{
handler_(static_cast<int>(exit_code), ec);
};

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;
@@ -55,15 +54,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>

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 auto len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
@@ -275,7 +277,9 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
const int len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
break;
p++;
}
@@ -288,7 +292,9 @@ public:
auto st1 = st + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr)
{
if (std::equal(st1.begin(), st1.end(), *p))
const int len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p))
return 1u;
p++;
}
@@ -672,7 +678,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 +699,7 @@ inline std::vector<boost::filesystem::path> path()
auto vec = itr->to_vector();
std::vector<boost::filesystem::path> val;
std::vector<boost::process::filesystem::path> val;
val.resize(vec.size());
std::copy(vec.begin(), vec.end(), val.begin());

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

@@ -8,6 +8,7 @@
#include <boost/process/detail/handler.hpp>
#include <boost/process/detail/used_handles.hpp>
#include <memory>
#if defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/executor.hpp>

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

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

@@ -76,9 +76,8 @@ inline std::locale default_locale()
std::locale global_loc = std::locale();
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
# else // Other POSIX
// ISO C calls std::locale("") "the locale-specific native environment", and this
// locale is the default for many POSIX-based operating systems such as Linux.
return std::locale("");
// Return a default locale object.
return std::locale();
# endif
}

View File

@@ -279,7 +279,7 @@ private:
else if (wrt == 0) //broken pipe
return false;
this->pbump(-wrt);
this->pbump(static_cast<int>(-wrt));
return true;
}

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 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,155 @@
// 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;
#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
#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(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__) || defined(__MACH__)
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)
{
ec.assign(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))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key, error_code & ec)
{
if (::unsetenv(key.c_str()))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
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)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
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()))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char_type, key_char_traits<char_type>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableW(key.c_str(), nullptr))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
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)
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
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()))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
void unset(basic_cstring_ref<char, key_char_traits<char>> key,
error_code & ec)
{
if (!::SetEnvironmentVariableA(key.c_str(), nullptr))
ec = ::BOOST_PROCESS_V2_NAMESPACE::detail::get_last_error();
}
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,48 @@
// 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
}
void throw_last_error()
{
throw system_error(get_last_error());
}
void throw_last_error(const char * msg)
{
throw system_error(get_last_error(), msg);
}
void throw_last_error(const std::string & msg)
{
throw system_error(get_last_error(), msg);
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_DETAIL_IMPL_LAST_ERROR_IPP

View File

@@ -0,0 +1,126 @@
// 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 <windows.h>
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))
ec = detail::get_last_error();
}
HANDLE open_process_(DWORD pid)
{
auto proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, pid);
if (proc == nullptr)
detail::throw_last_error("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)
{
ec.assign(ERROR_INVALID_HANDLE_STATE, system_category());
return false;
}
return true;
}
bool check_pid_(pid_type pid_, error_code & ec)
{
if (pid_ == 0)
{
ec.assign(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)
data->ec = detail::get_last_error();
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)))
ec = detail::get_last_error();
}
void interrupt_(pid_type pid_, error_code & ec)
{
if (!::GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid_))
ec = detail::get_last_error();
}
void terminate_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::TerminateProcess(handle, 260))
ec = detail::get_last_error();
}
void check_running_(HANDLE handle, error_code & ec, DWORD & exit_status)
{
if (!::GetExitCodeProcess(handle, &exit_status))
ec = detail::get_last_error();
}
#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:
ec.assign(error::insufficient_buffer, error::utf8_category);
break;
case ERROR_NO_UNICODE_TRANSLATION:
ec.assign(error::invalid_character, error::utf8_category);
break;
default:
ec.assign(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 instantitiated 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;
ec.assign(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);
ec.assign(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)
ec.assign(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;
ec.assign(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;
ec.assign(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;
ec.assign(error::insufficient_buffer, error::get_utf8_category());
return 0u;
}
*to++ = ucs_result;
}
from_next = from;
to_next = to;
if (from != from_end)
ec.assign(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,29 @@
// 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_DECL void throw_last_error();
BOOST_PROCESS_V2_DECL void throw_last_error(const char * msg);
BOOST_PROCESS_V2_DECL void throw_last_error(const std::string & msg);
}
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,318 @@
// 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_; }
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 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,346 @@
// 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_; }
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 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,314 @@
// 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() = delete;
};
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_; }
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 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,277 @@
// 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 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_(handle.handle_.get_executor())
{
}
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 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 occured 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::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 intepretations:
*
* - cancellation_type::total -> interrupt
* - cancellation_type::partial -> request_exit
* - cancellation_type::terminal -> terminate
*
* It is to note that `async_execute` will us the lowest seelected 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,250 @@
//
// 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
/** Convert the exit-code in a completion into an error if the actual error isn't set.
* @code {.cpp}
* process proc{ctx, "exit", {"1"}};
*
* proc.async_wait(code_as_error(
* [](error_code ec)
* {
* assert(ec.value() == 10);
* assert(ec.category() == error::get_exit_code_category());
* }));
*
* @endcode
*/
template<typename CompletionToken>
struct code_as_error_t
{
CompletionToken token_;
const error_category & category;
template<typename Token_>
code_as_error_t(Token_ && token, const error_category & category)
: token_(std::forward<Token_>(token)), category(category)
{
}
};
/// Deduction function for code_as_error_t.
template<typename CompletionToken>
code_as_error_t<CompletionToken> code_as_error(
CompletionToken && token,
const error_category & category = error::get_exit_code_category())
{
return code_as_error_t<typename std::decay<CompletionToken>::type>(
std::forward<CompletionToken>(token), category);
};
namespace detail
{
template<typename Handler>
struct code_as_error_handler
{
typedef void result_type;
template<typename H>
code_as_error_handler(H && h, const error_category & category)
: handler_(std::forward<H>(h)), category(category)
{
}
void operator()(error_code ec, native_exit_code_type code)
{
if (!ec)
ec.assign(code, category);
std::move(handler_)(ec);
}
Handler handler_;
const error_category & category;
};
}
BOOST_PROCESS_V2_END_NAMESPACE
#if !defined(BOOST_PROCESS_V2_STANDALONE)
namespace boost
{
#endif
namespace asio
{
template <typename CompletionToken>
struct async_result<
BOOST_PROCESS_V2_NAMESPACE::code_as_error_t<CompletionToken>,
void(BOOST_PROCESS_V2_NAMESPACE::error_code,
BOOST_PROCESS_V2_NAMESPACE::native_exit_code_type)>
{
using signature = void(BOOST_PROCESS_V2_NAMESPACE::error_code);
using return_type = typename async_result<CompletionToken, void(BOOST_PROCESS_V2_NAMESPACE::error_code)>::return_type;
template <typename Initiation>
struct init_wrapper
{
init_wrapper(Initiation init)
: initiation_(std::move(init))
{
}
template <typename Handler, typename... Args>
void operator()(
Handler && handler,
const BOOST_PROCESS_V2_NAMESPACE::error_category & cat,
Args && ... args)
{
std::move(initiation_)(
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<typename decay<Handler>::type>(
std::forward<Handler>(handler), cat),
std::forward<Args>(args)...);
}
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature,
(async_initiate<CompletionToken, signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<CompletionToken&>(),
declval<BOOST_ASIO_MOVE_ARG(Args)>()...)))
initiate(
Initiation && initiation,
RawCompletionToken && token,
Args &&... args)
{
return async_initiate<CompletionToken, signature>(
init_wrapper<typename decay<Initiation>::type>(
std::forward<Initiation>(initiation)),
token.token_,
token.category,
std::forward<Args>(args)...);
}
};
template<template <typename, typename> class Associator, typename Handler, typename DefaultCandidate>
struct associator<Associator,
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler> & h,
const DefaultCandidate& c = DefaultCandidate()) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
}
#if !defined(BOOST_PROCESS_V2_STANDALONE)
} // boost
#endif
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP

View File

@@ -0,0 +1,24 @@
//
// 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_IMPL_DEFAULT_LAUNCHER_IPP
#define BOOST_PROCESS_V2_IMPL_DEFAULT_LAUNCHER_IPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/windows/impl/default_launcher.ipp>
#else
#include <boost/process/v2/posix/detail/close_handles.ipp>
#endif
#endif //BOOST_PROCESS_V2_IMPL_DEFAULT_LAUNCHER_IPP

View File

@@ -0,0 +1,47 @@
//
// boost/process/v2/impl/environment.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_IMPL_ENVIRONMENT_IPP
#define BOOST_PROCESS_V2_IMPL_ENVIRONMENT_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/default_launcher.hpp>
#include <boost/process/v2/environment.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
error_code process_environment::on_setup(windows::default_launcher & launcher, const filesystem::path &, const std::wstring &)
{
if (!unicode_env.empty() && !ec)
{
launcher.creation_flags |= CREATE_UNICODE_ENVIRONMENT ;
launcher.environment = unicode_env.data();
}
return ec;
};
#else
error_code process_environment::on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
{
launcher.env = env.data();
return error_code{};
};
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_IMPL_ENVIRONMENT_IPP

View File

@@ -0,0 +1,206 @@
// 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_IMPL_ERROR_IPP
#define BOOST_PROCESS_V2_IMPL_ERROR_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/error.hpp>
#include <boost/process/v2/exit_code.hpp>
#include <cstdlib>
#if defined(BOOST_PROCESS_V2_POSIX)
#include <sys/wait.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace error
{
namespace detail
{
struct utf8_category final : public error_category
{
utf8_category() : error_category(0xDAEDu) {}
const char* name() const noexcept
{
return "process.v2.utf8";
}
std::string message(int value) const
{
switch (static_cast<utf8_conv_error>(value))
{
case utf8_conv_error::insufficient_buffer:
return "A supplied buffer size was not large enough";
case utf8_conv_error::invalid_character:
return "Invalid characters were found in a string.";
default:
return "process.v2.utf8 error";
}
}
};
struct exit_code_category final : public error_category
{
exit_code_category() : error_category(0xDAEEu) {}
const char* name() const noexcept
{
return "process.v2.exit_code";
}
std::string message(int status) const
{
switch (status)
{
case v2::detail::still_active:
return "still-active";
case EXIT_SUCCESS:
return "exit_success";
case EXIT_FAILURE:
return "exit_failure";
default:
#if defined(BOOST_PROCESS_V2_POSIX)
if (WIFCONTINUED(status))
return "continued";
switch (WTERMSIG(status))
{
# if defined(SIGABRT)
case SIGABRT: return "SIGABRT: Abort signal from abort(3)";
# endif
# if defined(SIGALRM)
case SIGALRM: return "SIGALRM: Timer signal from alarm(2)";
# endif
# if defined(SIGBUS)
case SIGBUS: return "SIGBUS: Bus error (bad memory access)";
# endif
# if defined(SIGCHLD)
case SIGCHLD: return "SIGCHLD: Child stopped or terminated";
# endif
# if defined(SIGCONT)
case SIGCONT: return "SIGCONT: Continue if stopped";
# endif
# if defined(SIGEMT)
case SIGEMT: return "SIGEMT: Emulator trap";
# endif
# if defined(SIGFPE)
case SIGFPE: return "SIGFPE: Floating-point exception";
# endif
# if defined(SIGHUP)
case SIGHUP: return "SIGHUP: Hangup detected on controlling terminal";
# endif
# if defined(SIGILL)
case SIGILL: return "SIGILL: Illegal Instruction";
# endif
# if defined(SIGINFO)
case SIGINFO: return "SIGINFO: A synonym for SIGPWR";
# endif
# if defined(SIGINT)
case SIGINT: return "SIGINT: Interrupt from keyboard";
# endif
# if defined(SIGIO)
case SIGIO: return "SIGIO: I/O now possible (4.2BSD)";
# endif
# if defined(SIGKILL)
case SIGKILL: return "SIGKILL: Kill signal";
# endif
# if defined(SIGLOST)
case SIGLOST: return "SIGLOST: File lock lost (unused)";
# endif
# if defined(SIGPIPE)
case SIGPIPE: return "SIGPIPE: Broken pipe: write to pipe with no";
# endif
# if defined(SIGPOLL) && !defined(SIGIO)
case SIGPOLL: return "SIGPOLL: Pollable event (Sys V);";
# endif
# if defined(SIGPROF)
case SIGPROF: return "SIGPROF: Profiling timer expired";
# endif
# if defined(SIGPWR)
case SIGPWR: return "SIGPWR: Power failure (System V)";
# endif
# if defined(SIGQUIT)
case SIGQUIT: return "SIGQUIT: Quit from keyboard";
# endif
# if defined(SIGSEGV)
case SIGSEGV: return "SIGSEGV: Invalid memory reference";
# endif
# if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT: Stack fault on coprocessor (unused)";
# endif
# if defined(SIGSTOP)
case SIGSTOP: return "SIGSTOP: Stop process";
# endif
# if defined(SIGTSTP)
case SIGTSTP: return "SIGTSTP: Stop typed at terminal";
# endif
# if defined(SIGSYS)
case SIGSYS: return "SIGSYS: Bad system call (SVr4);";
# endif
# if defined(SIGTERM)
case SIGTERM: return "SIGTERM: Termination signal";
# endif
# if defined(SIGTRAP)
case SIGTRAP: return "SIGTRAP: Trace/breakpoint trap";
# endif
# if defined(SIGTTIN)
case SIGTTIN: return "SIGTTIN: Terminal input for background process";
# endif
# if defined(SIGTTOU)
case SIGTTOU: return "SIGTTOU: Terminal output for background process";
# endif
# if defined(SIGURG)
case SIGURG: return "SIGURG: Urgent condition on socket (4.2BSD)";
# endif
# if defined(SIGUSR1)
case SIGUSR1: return "SIGUSR1: User-defined signal 1";
# endif
# if defined(SIGUSR2)
case SIGUSR2: return "SIGUSR2: User-defined signal 2";
# endif
# if defined(SIGVTALRM)
case SIGVTALRM: return "SIGVTALRM: Virtual alarm clock (4.2BSD)";
# endif
# if defined(SIGXCPU)
case SIGXCPU: return "SIGXCPU: CPU time limit exceeded (4.2BSD);";
# endif
# if defined(SIGXFSZ)
case SIGXFSZ: return "SIGXFSZ: File size limit exceeded (4.2BSD);";
# endif
# if defined(SIGWINCH)
case SIGWINCH: return "SIGWINCH: Window resize signal (4.3BSD, Sun)";
# endif
default: return "Unknown signal";
}
#endif
return "exited with other error";
}
}
};
} // namespace detail
BOOST_PROCESS_V2_DECL const error_category& get_utf8_category()
{
static detail::utf8_category instance;
return instance;
}
BOOST_PROCESS_V2_DECL const error_category& get_exit_code_category()
{
static detail::exit_code_category instance;
return instance;
}
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_IMPL_ERROR_IPP

View File

@@ -0,0 +1,27 @@
// 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_IMPL_PID_IPP
#define BOOST_PROCESS_V2_IMPL_PID_IPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/pid.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <windows.h>
#else
#include <unistd.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
pid_type current_pid() {return ::GetCurrentProcessId();}
#else
pid_type current_pid() {return ::getpid();}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_IMPL_PID_IPP

View File

@@ -0,0 +1,17 @@
// 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_IMPL_PROCESS_HANDLE_IPP
#define BOOST_PROCESS_V2_IMPL_PROCESS_HANDLE_IPP
#include <boost/process/v2/detail/config.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <boost/process/v2/detail/impl/process_handle_windows.ipp>
#else
#endif
#endif //BOOST_PROCESS_V2_IMPL_PROCESS_HANDLE_IPP

View File

@@ -0,0 +1,131 @@
// 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_IMPL_SHELL_IPP
#define BOOST_PROCESS_V2_IMPL_SHELL_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/config.hpp>
#include <boost/process/v2/error.hpp>
#include <boost/process/v2/shell.hpp>
#if defined(BOOST_PROCESS_V2_WINDOWS)
#include <shellapi.h>
#else
#include <wordexp.h>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(BOOST_PROCESS_V2_WINDOWS)
BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
{
return system_category();
}
#else
struct shell_category_t final : public error_category
{
shell_category_t() : error_category(0xDAF1u) {}
const char* name() const noexcept
{
return "process.v2.utf8";
}
std::string message(int value) const
{
switch (value)
{
case WRDE_BADCHAR:
return "Illegal occurrence of newline or one of |, &, ;, <, >, (, ), {, }.";
case WRDE_BADVAL:
return "An undefined shell variable was referenced, and the WRDE_UNDEF flag told us to consider this an error.";
case WRDE_CMDSUB:
return "Command substitution occurred, and the WRDE_NOCMD flag told us to consider this an error.";
case WRDE_NOSPACE:
return "Out of memory.";
case WRDE_SYNTAX:
return "Shell syntax error, such as unbalanced parentheses or unmatched quotes.";
default:
return "process.v2.wordexp error";
}
}
};
BOOST_PROCESS_V2_DECL const error_category& get_shell_category()
{
static shell_category_t instance;
return instance;
}
#endif
#if defined (BOOST_PROCESS_V2_WINDOWS)
void shell::parse_()
{
argv_ = ::CommandLineToArgvW(input_.c_str(), &argc_);
if (argv_ == nullptr)
detail::throw_last_error();
}
shell::~shell()
{
if (argv_ != nullptr)
LocalFree(argv_);
}
auto shell::args() const-> args_type
{
return input_.c_str();
}
#else
void shell::parse_()
{
wordexp_t we{};
auto cd = wordexp(input_.c_str(), &we, WRDE_NOCMD);
if (cd != 0)
detail::throw_error(error_code(cd, get_shell_category()), "shell::parse");
else
{
argc_ = static_cast<int>(we.we_wordc);
argv_ = we.we_wordv;
reserved_ = static_cast<int>(we.we_offs);
}
}
shell::~shell()
{
if (argv_ != nullptr)
{
wordexp_t we{
.we_wordc = static_cast<std::size_t>(argc_),
.we_wordv = argv_,
.we_offs = static_cast<std::size_t>(reserved_)
};
wordfree(&we);
}
}
auto shell::args() const -> args_type
{
if (argc() == 0)
{
static const char * helper = nullptr;
return &helper;
}
else
return const_cast<const char**>(argv());
}
#endif
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_IMPL_SHELL_IPP

View File

@@ -0,0 +1,41 @@
// 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_PID_HPP
#define BOOST_PROCESS_V2_PID_HPP
#include <boost/process/v2/detail/config.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
#if defined(GENERATING_DOCUMENTATION)
//An integral type representing a process id.
typedef implementation_defined pid_type;
#else
#if defined(BOOST_PROCESS_V2_WINDOWS)
typedef unsigned long pid_type;
#else
typedef int pid_type;
#endif
#endif
/// Get the process id of the current process.
BOOST_PROCESS_V2_DECL pid_type current_pid();
BOOST_PROCESS_V2_END_NAMESPACE
#if defined(BOOST_PROCESS_V2_HEADER_ONLY)
#include <boost/process/v2/impl/pid.ipp>
#endif
#endif //BOOST_PROCESS_V2_PID_HPP

View File

@@ -0,0 +1,514 @@
// 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_POPEN_HPP
#define BOOST_PROCESS_V2_POPEN_HPP
#include <boost/process/v2/process.hpp>
#include <boost/process/v2/stdio.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/connect_pipe.hpp>
#include <asio/readable_pipe.hpp>
#include <asio/writable_pipe.hpp>
#else
#include <boost/asio/connect_pipe.hpp>
#include <boost/asio/readable_pipe.hpp>
#include <boost/asio/writable_pipe.hpp>
#endif
BOOST_PROCESS_V2_BEGIN_NAMESPACE
/// A subprocess with automatically assigned pipes.
/** The purpose os the popen is to provide a convenient way
* to use the stdin & stdout of a process.
*
* @code {.cpp}
* popen proc(executor, find_executable("addr2line"), {argv[0]});
* asio::write(proc, asio::buffer("main\n"));
* std::string line;
* asio::read_until(proc, asio::dynamic_buffer(line), '\n');
* @endcode
*
*
* Popen can be used as a stream object in other protocols.
*/
template<typename Executor = BOOST_PROCESS_V2_ASIO_NAMESPACE::any_io_executor>
struct basic_popen : basic_process<Executor>
{
/// The executor of the process
using executor_type = Executor;
/// Rebinds the popen type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_popen<Executor1> other;
};
/// Move construct a popen
basic_popen(basic_popen &&) = default;
/// Move assign a popen
basic_popen& operator=(basic_popen &&) = default;
/// Move construct a popen and change the executor type.
template<typename Executor1>
basic_popen(basic_popen<Executor1>&& lhs)
: basic_process<Executor>(std::move(lhs)),
stdin_(std::move(lhs.stdin_)), stdout_(std::move(lhs.stdout_))
{
}
/// Create a closed process handle
explicit basic_popen(executor_type exec) : basic_process<Executor>{std::move(exec)} {}
/// Create a closed process handle
template <typename ExecutionContext>
explicit basic_popen(ExecutionContext & context,
typename std::enable_if<
is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, void *>::type = nullptr)
: basic_process<Executor>{context}
{
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits>
explicit basic_popen(
executor_type executor,
const filesystem::path& exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits>
explicit basic_popen(
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Args, typename ... Inits>
explicit basic_popen(
executor_type executor,
const filesystem::path& exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
default_process_launcher()(
std::move(executor), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
std::move(executor), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename ... Inits>
explicit basic_popen(
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen(
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
default_process_launcher()(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// The type used for stdin on the parent process side.
using stdin_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor>;
/// The type used for stdout on the parent process side.
using stdout_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_readable_pipe<Executor>;
/// Get the stdin pipe.
stdin_type & get_stdin() {return stdin_; }
/// Get the stdout pipe.
stdout_type & get_stdout() {return stdout_; }
/// Get the stdin pipe.
const stdin_type & get_stdin() const {return stdin_; }
/// Get the stdout pipe.
const stdout_type & get_stdout() const {return stdout_; }
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @returns The number of bytes written.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* subprocess.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.write_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return stdin_.write_some(buffers);
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* subprocess. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
boost::system::error_code& ec)
{
return stdin_.write_some(buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more data buffers to be written to the pipe.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::post().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* popen.async_write_some(boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) WriteToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (boost::system::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
BOOST_ASIO_MOVE_ARG(WriteToken) token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stdin_.async_write_some(buffers, std::forward<WriteToken>(token));
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws boost::system::system_error Thrown on failure. An error code of
* boost::asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.read_some(boost::asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return stdout_.read_some(buffers);
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
boost::system::error_code& ec)
{
return stdout_.read_some(buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const boost::system::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using boost::asio::post().
*
* @par Completion Signature
* @code void(boost::system::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.async_read_some(
* boost::asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence,
BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code,
std::size_t)) ReadToken
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (boost::system::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
BOOST_ASIO_MOVE_ARG(ReadToken) token
BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stdout_.async_read_some(buffers, std::forward<ReadToken>(token));
}
private:
stdin_type stdin_ {basic_process<Executor>::get_executor()};
stdout_type stdout_{basic_process<Executor>::get_executor()};
};
/// A popen object with the default executor.
using popen = basic_popen<>;
BOOST_PROCESS_V2_END_NAMESPACE
#endif //BOOST_PROCESS_V2_POPEN_HPP

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