|
|
@@ -37,33 +37,40 @@ |
|
|
|
|
|
|
|
namespace CodeDweller {
|
|
|
|
|
|
|
|
ChildStream::ChildStream(std::vector<std::string> args, size_t bufSize) :
|
|
|
|
ChildStream::ChildStream(std::vector<std::string> const &args,
|
|
|
|
size_t bufSize) :
|
|
|
|
childStreambuf(bufSize),
|
|
|
|
std::iostream(&childStreambuf),
|
|
|
|
cmdArgs(args) {
|
|
|
|
|
|
|
|
init();
|
|
|
|
run();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ChildStream::ChildStream(std::string childpath, size_t bufSize) :
|
|
|
|
ChildStream::ChildStream(std::string const &childpath, size_t bufSize) :
|
|
|
|
childStreambuf(bufSize),
|
|
|
|
std::iostream(&childStreambuf),
|
|
|
|
cmdline(childpath) {
|
|
|
|
std::iostream(&childStreambuf) {
|
|
|
|
|
|
|
|
cmdArgs.push_back(childpath);
|
|
|
|
init();
|
|
|
|
run();
|
|
|
|
}
|
|
|
|
|
|
|
|
ChildStream::~ChildStream() {
|
|
|
|
// Close handles.
|
|
|
|
}
|
|
|
|
ChildStream::ChildStream(size_t bufSize) :
|
|
|
|
childStreambuf(bufSize),
|
|
|
|
std::iostream(&childStreambuf) {
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildStream::init() {
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmdArgs.empty()) {
|
|
|
|
throw std::invalid_argument("A child executable must be specified.");
|
|
|
|
ChildStream::~ChildStream() {
|
|
|
|
if (isRunning()) {
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChildStream::init() {
|
|
|
|
|
|
|
|
childStarted = false;
|
|
|
|
childExited = false;
|
|
|
@@ -71,21 +78,40 @@ namespace CodeDweller { |
|
|
|
exitCode = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
ChildStream::numBytesAvailable() const {
|
|
|
|
void ChildStream::open(std::vector<std::string> const &args) {
|
|
|
|
cmdArgs = args;
|
|
|
|
init();
|
|
|
|
run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChildStream::open(std::string const &childpath) {
|
|
|
|
cmdArgs.clear();
|
|
|
|
cmdArgs.push_back(childpath);
|
|
|
|
init();
|
|
|
|
run();
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ChildStream::numBytesAvailable() const {
|
|
|
|
|
|
|
|
return childStreambuf.numBytesAvailable();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildStream::run() {
|
|
|
|
bool ChildStream::isRunning() const {
|
|
|
|
return childStarted && !childExited;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ChildStream::run() {
|
|
|
|
|
|
|
|
if (childStarted) {
|
|
|
|
throw std::logic_error("Child process was active when "
|
|
|
|
"run() was called");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmdArgs.empty()) {
|
|
|
|
throw std::invalid_argument("A child executable must be specified.");
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
// Set the bInheritHandle flag so pipe handles are inherited.
|
|
|
|
SECURITY_ATTRIBUTES securityAttributes;
|
|
|
@@ -221,8 +247,8 @@ namespace CodeDweller { |
|
|
|
getErrorText());
|
|
|
|
}
|
|
|
|
if (pipe(childStdOutPipe) != 0) {
|
|
|
|
close(childStdInPipe[0]);
|
|
|
|
close(childStdInPipe[1]);
|
|
|
|
::close(childStdInPipe[0]);
|
|
|
|
::close(childStdInPipe[1]);
|
|
|
|
throw std::runtime_error("Error creating pipe for stdout: " +
|
|
|
|
getErrorText());
|
|
|
|
}
|
|
|
@@ -231,8 +257,8 @@ namespace CodeDweller { |
|
|
|
childPid = fork();
|
|
|
|
if (-1 == childPid) {
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
close(childStdInPipe[i]);
|
|
|
|
close(childStdOutPipe[i]);
|
|
|
|
::close(childStdInPipe[i]);
|
|
|
|
::close(childStdOutPipe[i]);
|
|
|
|
}
|
|
|
|
throw std::runtime_error("Error creating child process: " +
|
|
|
|
getErrorText());
|
|
|
@@ -261,10 +287,10 @@ namespace CodeDweller { |
|
|
|
}
|
|
|
|
|
|
|
|
// Close pipes.
|
|
|
|
if ( (close(childStdInPipe[0]) != 0) ||
|
|
|
|
(close(childStdInPipe[1]) != 0) ||
|
|
|
|
(close(childStdOutPipe[0]) != 0) ||
|
|
|
|
(close(childStdOutPipe[1]) != 0) ) {
|
|
|
|
if ( (::close(childStdInPipe[0]) != 0) ||
|
|
|
|
(::close(childStdInPipe[1]) != 0) ||
|
|
|
|
(::close(childStdOutPipe[0]) != 0) ||
|
|
|
|
(::close(childStdOutPipe[1]) != 0) ) {
|
|
|
|
std::string errMsg;
|
|
|
|
|
|
|
|
// Send message to parent.
|
|
|
@@ -295,16 +321,14 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// std::cout << "Child pid: " << childPid << std::endl; // DEBUG.
|
|
|
|
|
|
|
|
// Provide the stream buffers with the file descriptors for
|
|
|
|
// communicating with the child process.
|
|
|
|
childStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
|
|
|
|
childStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
|
|
|
|
|
|
|
|
// Close the child's end of the pipes.
|
|
|
|
if ( (close(childStdInPipe[0]) != 0) ||
|
|
|
|
(close(childStdOutPipe[1]) != 0) ) {
|
|
|
|
if ( (::close(childStdInPipe[0]) != 0) ||
|
|
|
|
(::close(childStdOutPipe[1]) != 0) ) {
|
|
|
|
std::string errMsg;
|
|
|
|
|
|
|
|
throw std::runtime_error("Error closing child's end of pipes in "
|
|
|
@@ -317,8 +341,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildStream::terminate() {
|
|
|
|
void ChildStream::close() {
|
|
|
|
|
|
|
|
if (isDone()) {
|
|
|
|
|
|
|
@@ -337,8 +360,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ChildStream::isDone() {
|
|
|
|
bool ChildStream::isDone() {
|
|
|
|
|
|
|
|
if (childExited) {
|
|
|
|
|
|
|
@@ -399,8 +421,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int32_t
|
|
|
|
ChildStream::result() {
|
|
|
|
int32_t ChildStream::result() {
|
|
|
|
|
|
|
|
if (exitCodeObtainedFlag) {
|
|
|
|
|
|
|
@@ -427,8 +448,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string
|
|
|
|
ChildStream::getErrorText() {
|
|
|
|
std::string ChildStream::getErrorText() {
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
LPVOID winMsgBuf;
|
|
|
@@ -479,23 +499,20 @@ namespace CodeDweller { |
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
void
|
|
|
|
ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
|
|
|
|
void ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
|
|
|
|
|
|
|
|
inputHandle = inHandle;
|
|
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
|
|
ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
|
|
|
|
void ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
|
|
|
|
|
|
|
|
inputFileDescriptor = inFd;
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
size_t
|
|
|
|
ChildStream::ChildStreambuf::numBytesAvailable() const {
|
|
|
|
size_t ChildStream::ChildStreambuf::numBytesAvailable() const {
|
|
|
|
|
|
|
|
size_t nBytesAvailable = egptr() - gptr();
|
|
|
|
|
|
|
@@ -537,8 +554,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::streambuf::int_type
|
|
|
|
ChildStream::ChildStreambuf::underflow() {
|
|
|
|
std::streambuf::int_type ChildStream::ChildStreambuf::underflow() {
|
|
|
|
|
|
|
|
// Check for empty buffer.
|
|
|
|
if (gptr() < egptr()) {
|
|
|
@@ -595,23 +611,20 @@ namespace CodeDweller { |
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
void
|
|
|
|
ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
|
|
|
|
void ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
|
|
|
|
|
|
|
|
outputHandle = outHandle;
|
|
|
|
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void
|
|
|
|
ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
|
|
|
|
void ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
|
|
|
|
|
|
|
|
outputFileDescriptor = outFd;
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
ChildStream::ChildStreambuf::flushBuffer() {
|
|
|
|
void ChildStream::ChildStreambuf::flushBuffer() {
|
|
|
|
|
|
|
|
// Write.
|
|
|
|
std::ptrdiff_t nBytes = pptr() - pbase();
|
|
|
@@ -648,8 +661,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::streambuf::int_type
|
|
|
|
ChildStream::ChildStreambuf::overflow(int_type ch) {
|
|
|
|
std::streambuf::int_type ChildStream::ChildStreambuf::overflow(int_type ch) {
|
|
|
|
|
|
|
|
// Check whether we're writing EOF.
|
|
|
|
if (traits_type::eof() != ch) {
|
|
|
@@ -670,8 +682,7 @@ namespace CodeDweller { |
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
ChildStream::ChildStreambuf::sync() {
|
|
|
|
int ChildStream::ChildStreambuf::sync() {
|
|
|
|
|
|
|
|
flushBuffer(); // Throws exception on failure.
|
|
|
|
|