@@ -65,13 +65,9 @@ Documentation for C++ subprocessing library.
6565
6666extern " C" {
6767#ifdef __USING_WINDOWS__
68- #include < Windows .h>
68+ #include < windows .h>
6969 #include < io.h>
7070 #include < cwchar>
71-
72- #define close _close
73- #define open _open
74- #define fileno _fileno
7571#else
7672 #include < sys/wait.h>
7773 #include < unistd.h>
@@ -81,6 +77,22 @@ extern "C" {
8177 #include < sys/types.h>
8278}
8379
80+ // The Microsoft C++ compiler issues deprecation warnings
81+ // for the standard POSIX function names.
82+ // Its preferred implementations have a leading underscore.
83+ // See: https://learn.microsoft.com/en-us/cpp/c-runtime-library/compatibility.
84+ #if (defined _MSC_VER)
85+ #define subprocess_close _close
86+ #define subprocess_fileno _fileno
87+ #define subprocess_open _open
88+ #define subprocess_write _write
89+ #else
90+ #define subprocess_close close
91+ #define subprocess_fileno fileno
92+ #define subprocess_open open
93+ #define subprocess_write write
94+ #endif
95+
8496/* !
8597 * Getting started with reading this source code.
8698 * The source is mainly divided into four parts:
@@ -159,6 +171,7 @@ class OSError: public std::runtime_error
159171// --------------------------------------------------------------------
160172namespace util
161173{
174+ #ifdef __USING_WINDOWS__
162175 inline void quote_argument (const std::wstring &argument, std::wstring &command_line,
163176 bool force)
164177 {
@@ -169,7 +182,7 @@ namespace util
169182 //
170183
171184 if (force == false && argument.empty () == false &&
172- argument.find_first_of (L" \t\n\v\" " ) == argument.npos ) {
185+ argument.find_first_of (L" \t\n\v " ) == argument.npos ) {
173186 command_line.append (argument);
174187 }
175188 else {
@@ -219,7 +232,6 @@ namespace util
219232 }
220233 }
221234
222- #ifdef __USING_WINDOWS__
223235 inline std::string get_last_error (DWORD errorMessageID)
224236 {
225237 if (errorMessageID == 0 )
@@ -264,7 +276,7 @@ namespace util
264276
265277 FILE *fp = _fdopen (os_fhandle, mode);
266278 if (fp == 0 ) {
267- _close (os_fhandle);
279+ subprocess_close (os_fhandle);
268280 throw OSError (" _fdopen" , 0 );
269281 }
270282
@@ -334,10 +346,14 @@ namespace util
334346 void set_clo_on_exec (int fd, bool set = true )
335347 {
336348 int flags = fcntl (fd, F_GETFD, 0 );
349+ if (flags == -1 ) {
350+ throw OSError (" fcntl F_GETFD failed" , errno);
351+ }
337352 if (set) flags |= FD_CLOEXEC;
338353 else flags &= ~FD_CLOEXEC;
339- // TODO: should check for errors
340- fcntl (fd, F_SETFD, flags);
354+ if (fcntl (fd, F_SETFD, flags) == -1 ) {
355+ throw OSError (" fcntl F_SETFD failed" , errno);
356+ }
341357 }
342358
343359
@@ -383,7 +399,7 @@ namespace util
383399 {
384400 size_t nwritten = 0 ;
385401 while (nwritten < length) {
386- int written = write (fd, buf + nwritten, length - nwritten);
402+ int written = subprocess_write (fd, buf + nwritten, length - nwritten);
387403 if (written == -1 ) return -1 ;
388404 nwritten += written;
389405 }
@@ -411,7 +427,7 @@ namespace util
411427#ifdef __USING_WINDOWS__
412428 return (int )fread (buf, 1 , read_upto, fp);
413429#else
414- int fd = fileno (fp);
430+ int fd = subprocess_fileno (fp);
415431 int rbytes = 0 ;
416432 int eintr_cnter = 0 ;
417433
@@ -527,7 +543,7 @@ struct string_arg
527543{
528544 string_arg (const char * arg): arg_value(arg) {}
529545 string_arg (std::string&& arg): arg_value(std::move(arg)) {}
530- string_arg (std::string arg): arg_value(std::move( arg) ) {}
546+ string_arg (const std::string& arg): arg_value(arg) {}
531547 std::string arg_value;
532548};
533549
@@ -573,10 +589,10 @@ struct input
573589 explicit input (int fd): rd_ch_(fd) {}
574590
575591 // FILE pointer.
576- explicit input (FILE* fp):input(fileno (fp)) { assert (fp); }
592+ explicit input (FILE* fp):input(subprocess_fileno (fp)) { assert (fp); }
577593
578594 explicit input (const char * filename) {
579- int fd = open (filename, O_RDONLY);
595+ int fd = subprocess_open (filename, O_RDONLY);
580596 if (fd == -1 ) throw OSError (" File not found: " , errno);
581597 rd_ch_ = fd;
582598 }
@@ -606,10 +622,10 @@ struct output
606622{
607623 explicit output (int fd): wr_ch_(fd) {}
608624
609- explicit output (FILE* fp):output(fileno (fp)) { assert (fp); }
625+ explicit output (FILE* fp):output(subprocess_fileno (fp)) { assert (fp); }
610626
611627 explicit output (const char * filename) {
612- int fd = open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
628+ int fd = subprocess_open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
613629 if (fd == -1 ) throw OSError (" File not found: " , errno);
614630 wr_ch_ = fd;
615631 }
@@ -637,10 +653,10 @@ struct error
637653{
638654 explicit error (int fd): wr_ch_(fd) {}
639655
640- explicit error (FILE* fp):error(fileno (fp)) { assert (fp); }
656+ explicit error (FILE* fp):error(subprocess_fileno (fp)) { assert (fp); }
641657
642658 explicit error (const char * filename) {
643- int fd = open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
659+ int fd = subprocess_open (filename, O_APPEND | O_CREAT | O_RDWR, 0640 );
644660 if (fd == -1 ) throw OSError (" File not found: " , errno);
645661 wr_ch_ = fd;
646662 }
@@ -758,7 +774,10 @@ class Communication
758774public:
759775 Communication (Streams* stream): stream_(stream)
760776 {}
761- void operator =(const Communication&) = delete ;
777+ Communication (const Communication&) = delete ;
778+ Communication& operator =(const Communication&) = delete ;
779+ Communication (Communication&&) = default ;
780+ Communication& operator =(Communication&&) = default ;
762781public:
763782 int send (const char * msg, size_t length);
764783 int send (const std::vector<char >& msg);
@@ -795,36 +814,39 @@ class Streams
795814{
796815public:
797816 Streams ():comm_(this ) {}
798- void operator =(const Streams&) = delete ;
817+ Streams (const Streams&) = delete ;
818+ Streams& operator =(const Streams&) = delete ;
819+ Streams (Streams&&) = default ;
820+ Streams& operator =(Streams&&) = default ;
799821
800822public:
801823 void setup_comm_channels ();
802824
803825 void cleanup_fds ()
804826 {
805827 if (write_to_child_ != -1 && read_from_parent_ != -1 ) {
806- close (write_to_child_);
828+ subprocess_close (write_to_child_);
807829 }
808830 if (write_to_parent_ != -1 && read_from_child_ != -1 ) {
809- close (read_from_child_);
831+ subprocess_close (read_from_child_);
810832 }
811833 if (err_write_ != -1 && err_read_ != -1 ) {
812- close (err_read_);
834+ subprocess_close (err_read_);
813835 }
814836 }
815837
816838 void close_parent_fds ()
817839 {
818- if (write_to_child_ != -1 ) close (write_to_child_);
819- if (read_from_child_ != -1 ) close (read_from_child_);
820- if (err_read_ != -1 ) close (err_read_);
840+ if (write_to_child_ != -1 ) subprocess_close (write_to_child_);
841+ if (read_from_child_ != -1 ) subprocess_close (read_from_child_);
842+ if (err_read_ != -1 ) subprocess_close (err_read_);
821843 }
822844
823845 void close_child_fds ()
824846 {
825- if (write_to_parent_ != -1 ) close (write_to_parent_);
826- if (read_from_parent_ != -1 ) close (read_from_parent_);
827- if (err_write_ != -1 ) close (err_write_);
847+ if (write_to_parent_ != -1 ) subprocess_close (write_to_parent_);
848+ if (read_from_parent_ != -1 ) subprocess_close (read_from_parent_);
849+ if (err_write_ != -1 ) subprocess_close (err_write_);
828850 }
829851
830852 FILE* input () { return input_.get (); }
@@ -1043,7 +1065,19 @@ inline int Popen::wait() noexcept(false)
10431065#ifdef __USING_WINDOWS__
10441066 int ret = WaitForSingleObject (process_handle_, INFINITE);
10451067
1046- return 0 ;
1068+ // WaitForSingleObject with INFINITE should only return when process has signaled
1069+ if (ret != WAIT_OBJECT_0) {
1070+ throw OSError (" Unexpected return code from WaitForSingleObject" , 0 );
1071+ }
1072+
1073+ DWORD dretcode_;
1074+
1075+ if (FALSE == GetExitCodeProcess (process_handle_, &dretcode_))
1076+ throw OSError (" Failed during call to GetExitCodeProcess" , 0 );
1077+
1078+ CloseHandle (process_handle_);
1079+
1080+ return (int )dretcode_;
10471081#else
10481082 int ret, status;
10491083 std::tie (ret, status) = util::wait_for_child_exit (child_pid_);
@@ -1156,8 +1190,8 @@ inline void Popen::execute_process() noexcept(false)
11561190 child_pid_ = fork ();
11571191
11581192 if (child_pid_ < 0 ) {
1159- close (err_rd_pipe);
1160- close (err_wr_pipe);
1193+ subprocess_close (err_rd_pipe);
1194+ subprocess_close (err_wr_pipe);
11611195 throw OSError (" fork failed" , errno);
11621196 }
11631197
@@ -1167,25 +1201,27 @@ inline void Popen::execute_process() noexcept(false)
11671201 stream_.close_parent_fds ();
11681202
11691203 // Close the read end of the error pipe
1170- close (err_rd_pipe);
1204+ subprocess_close (err_rd_pipe);
11711205
11721206 detail::Child chld (this , err_wr_pipe);
11731207 chld.execute_child ();
11741208 }
11751209 else
11761210 {
1177- close (err_wr_pipe);// close child side of pipe, else get stuck in read below
1211+ subprocess_close (err_wr_pipe);// close child side of pipe, else get stuck in read below
11781212
11791213 stream_.close_child_fds ();
11801214
11811215 try {
11821216 char err_buf[SP_MAX_ERR_BUF_SIZ] = {0 ,};
11831217
1184- int read_bytes = util::read_atmost_n (
1185- fdopen (err_rd_pipe, " r" ),
1186- err_buf,
1187- SP_MAX_ERR_BUF_SIZ);
1188- close (err_rd_pipe);
1218+ FILE* err_fp = fdopen (err_rd_pipe, " r" );
1219+ if (!err_fp) {
1220+ subprocess_close (err_rd_pipe);
1221+ throw OSError (" fdopen failed" , errno);
1222+ }
1223+ int read_bytes = util::read_atmost_n (err_fp, err_buf, SP_MAX_ERR_BUF_SIZ);
1224+ fclose (err_fp);
11891225
11901226 if (read_bytes || strlen (err_buf)) {
11911227 // Call waitpid to reap the child process
@@ -1271,13 +1307,13 @@ namespace detail {
12711307
12721308 // Close the duped descriptors
12731309 if (stream.read_from_parent_ != -1 && stream.read_from_parent_ > 2 )
1274- close (stream.read_from_parent_ );
1310+ subprocess_close (stream.read_from_parent_ );
12751311
12761312 if (stream.write_to_parent_ != -1 && stream.write_to_parent_ > 2 )
1277- close (stream.write_to_parent_ );
1313+ subprocess_close (stream.write_to_parent_ );
12781314
12791315 if (stream.err_write_ != -1 && stream.err_write_ > 2 )
1280- close (stream.err_write_ );
1316+ subprocess_close (stream.err_write_ );
12811317
12821318 // Replace the current image with the executable
12831319 sys_ret = execvp (parent_->exe_name_ .c_str (), parent_->cargv_ .data ());
@@ -1304,15 +1340,15 @@ namespace detail {
13041340#ifdef __USING_WINDOWS__
13051341 util::configure_pipe (&this ->g_hChildStd_IN_Rd , &this ->g_hChildStd_IN_Wr , &this ->g_hChildStd_IN_Wr );
13061342 this ->input (util::file_from_handle (this ->g_hChildStd_IN_Wr , " w" ));
1307- this ->write_to_child_ = _fileno (this ->input ());
1343+ this ->write_to_child_ = subprocess_fileno (this ->input ());
13081344
13091345 util::configure_pipe (&this ->g_hChildStd_OUT_Rd , &this ->g_hChildStd_OUT_Wr , &this ->g_hChildStd_OUT_Rd );
13101346 this ->output (util::file_from_handle (this ->g_hChildStd_OUT_Rd , " r" ));
1311- this ->read_from_child_ = _fileno (this ->output ());
1347+ this ->read_from_child_ = subprocess_fileno (this ->output ());
13121348
13131349 util::configure_pipe (&this ->g_hChildStd_ERR_Rd , &this ->g_hChildStd_ERR_Wr , &this ->g_hChildStd_ERR_Rd );
13141350 this ->error (util::file_from_handle (this ->g_hChildStd_ERR_Rd , " r" ));
1315- this ->err_read_ = _fileno (this ->error ());
1351+ this ->err_read_ = subprocess_fileno (this ->error ());
13161352#else
13171353
13181354 if (write_to_child_ != -1 ) input (fdopen (write_to_child_, " wb" ));
0 commit comments