| 
				
			 | 
			
			 | 
			@@ -20,14 +20,17 @@ | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			//==============================================================================
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include <iostream> // Temporary.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include <stdexcept>
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			#include "child.hpp"
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			namespace CodeDweller {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::Child(std::vector<std::string> args) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::Child(std::vector<std::string> args, size_t bufSize) :
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    readStreambuf(bufSize),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    writeStreambuf(bufSize),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    reader(&readStreambuf),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    writer(&writeStreambuf) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    init();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -45,33 +48,34 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    cmdline += args.back(); // Append last command-line argument.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::Child(std::string childpath) :
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::Child(std::string childpath, size_t bufSize) :
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    readStreambuf(bufSize),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    writeStreambuf(bufSize),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    reader(&readStreambuf),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    writer(&writeStreambuf),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    cmdline(childpath) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    init();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::~Child() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Close handles.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::init() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    childStarted = false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCodeObtainedFlag = false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCode = 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::istream *
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::reader() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return new std::istream(std::cin.rdbuf());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::ostream *
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::writer() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return new std::ostream(std::cout.rdbuf());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::run() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (childStarted) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::logic_error("Child process was active when "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						     "run() was called");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Set the bInheritHandle flag so pipe handles are inherited. 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   SECURITY_ATTRIBUTES securityAttributes; 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -81,7 +85,9 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // Create a pipe for the child process's STDOUT.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   HANDLE childStdOutAtChild;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   HANDLE childStdOutAtParent;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   HANDLE childStdInAtChild;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   HANDLE childStdInAtParent;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   int bufferSize = 0;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   if (!CreatePipe(&childStdOutAtParent,
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -139,39 +145,59 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   startInfo.dwFlags |= STARTF_USESTDHANDLES;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // Create the child process. 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   bool createSuccess;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   bool status;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   createSuccess = CreateProcess(NULL, 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 (char *) cmdline.c_str(), // command line 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 NULL,         	  // process security attributes 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 NULL,         	  // primary thread security attributes 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 true,         	  // handles are inherited 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 0,            	  // creation flags 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 NULL,         	  // use parent's environment 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 NULL,         	  // use parent's current directory 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 &startInfo,   	  // STARTUPINFO pointer 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
							 &processInfo);	  // receives PROCESS_INFORMATION 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   status = CreateProcess(NULL, 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  (char *) cmdline.c_str(), // command line 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  NULL,         	    // process security attributes 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  NULL,         	    // primary thread security attributes 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  true,         	    // handles are inherited 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  0,            	    // creation flags 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  NULL,         	    // use parent's environment 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  NULL,         	    // use parent's current directory 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  &startInfo,   	    // STARTUPINFO pointer 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						  &processInfo);	    // receives PROCESS_INFORMATION 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // If an error occurs, exit the application. 
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   if (!createSuccess ) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   if (!status ) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     throw std::runtime_error("Error from CreateProcess with "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						      "command line \"" + cmdline + "\":  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						      getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // Provide the stream buffers with the handles for communicating
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // with the child process.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   readStreambuf.setInputHandle(childStdOutAtParent);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   writeStreambuf.setOutputHandle(childStdInAtParent);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // Save the handles to the child process and its primary thread.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   childProcess = processInfo.hProcess;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   childThread = processInfo.hThread;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   childStarted = true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   // Close the child's end of the pipes.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   CloseHandle(childStdOutAtChild);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   CloseHandle(childStdInAtChild);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   if (!CloseHandle(childStdOutAtChild)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Error closing the child process stdout handle:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			     
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			   if (!CloseHandle(childStdInAtChild)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Error closing the child process stdin handle:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::terminate() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (isDone()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!TerminateProcess(childProcess, terminateExitCode)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Error terminating the child process:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -179,9 +205,55 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  bool
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::isDone() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (exitCodeObtainedFlag) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!childStarted) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::logic_error("Child process was not started "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						     "when isDone() was called");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Error checking status of child process:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (STILL_ACTIVE == result) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return false;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Child process has exited.  Save the exit code.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCode = result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCodeObtainedFlag = true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  int32_t
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::result() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (exitCodeObtainedFlag) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return exitCode;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!childStarted) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::logic_error("Child process was not started "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						     "when result() was called");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    int result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -189,6 +261,16 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Error if the process has not exited.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (STILL_ACTIVE == result) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::logic_error("Child process was active when "
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						     "result() was called");
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Child process has exited.  Save the exit code.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCode = result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    exitCodeObtainedFlag = true;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return result;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
	
		
			
			| 
				
			 | 
			
			 | 
			@@ -214,4 +296,138 @@ namespace CodeDweller { | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return errMsg;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    inputHandle(0),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    buffer(bufferSize + 1) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    char *end = &(buffer.front()) + buffer.size();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Indicate to underflow that underflow has not been called.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    setg(end, end, end);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    inputHandle = inHandle;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::streambuf::int_type
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::ReadStreambuf::underflow() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check for empty buffer.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (gptr() < egptr()) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Not empty.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return traits_type::to_int_type(*gptr());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Need to fill the buffer.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    char *base = &(buffer.front());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    char *start = base;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check whether this is the first fill.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (eback() == base) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Not the first fill.  Copy putback characters.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // start points to the start of the buffer.  Fill buffer.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    DWORD nBytesRead;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!ReadFile(inputHandle,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					  start,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					  buffer.size() - (start - base),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					  &nBytesRead,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					  NULL)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return traits_type::eof();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check for EOF.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (0 == nBytesRead) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      return traits_type::eof();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Update buffer pointers.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    setg(base, start, start + nBytesRead);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return traits_type::to_int_type(*gptr());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::WriteStreambuf::WriteStreambuf(std::size_t bufferSize) :
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    outputHandle(0),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    buffer(bufferSize + 1) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    char *base = &(buffer.front());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Indicate to overflow that overflow has not been called.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    setp(base, base + buffer.size() - 1);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    outputHandle = outHandle;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  void
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::WriteStreambuf::flushBuffer() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Write.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    std::ptrdiff_t nBytes = pptr() - pbase();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    DWORD nBytesWritten;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (!WriteFile(outputHandle,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					   pbase(),
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					   nBytes,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					   &nBytesWritten,
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
					   NULL)) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Error writing to child process:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (nBytes != nBytesWritten) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      throw std::runtime_error("Not all data was written to to child process:  " +
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
						       getErrorText());
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    pbump(-nBytes);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  std::streambuf::int_type
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::WriteStreambuf::overflow(int_type ch) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Check whether we're writing EOF.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    if (traits_type::eof() != ch) {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      // Not writing EOF.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      *(pptr()) = ch;
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			      pbump(1);
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Write.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    flushBuffer();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    // Success.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return traits_type::not_eof('a');
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  int
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  Child::WriteStreambuf::sync() {
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    flushBuffer();
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			    return 1; // Success.
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			  }
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			
 | 
		
		
	
		
			
			 | 
			 | 
			
			 | 
			}
 |