|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace CodeDweller {
|
|
|
namespace CodeDweller {
|
|
|
|
|
|
|
|
|
Child::Child(std::vector<std::string> args, size_t bufSize) :
|
|
|
|
|
|
|
|
|
ChildStream::ChildStream(std::vector<std::string> args, size_t bufSize) :
|
|
|
childStreambuf(bufSize),
|
|
|
childStreambuf(bufSize),
|
|
|
childStream(&childStreambuf),
|
|
|
|
|
|
|
|
|
std::iostream(&childStreambuf),
|
|
|
cmdArgs(args) {
|
|
|
cmdArgs(args) {
|
|
|
|
|
|
|
|
|
init();
|
|
|
init();
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
Child::Child(std::string childpath, size_t bufSize) :
|
|
|
|
|
|
|
|
|
ChildStream::ChildStream(std::string childpath, size_t bufSize) :
|
|
|
childStreambuf(bufSize),
|
|
|
childStreambuf(bufSize),
|
|
|
childStream(&childStreambuf),
|
|
|
|
|
|
|
|
|
std::iostream(&childStreambuf),
|
|
|
cmdline(childpath) {
|
|
|
cmdline(childpath) {
|
|
|
cmdArgs.push_back(childpath);
|
|
|
cmdArgs.push_back(childpath);
|
|
|
init();
|
|
|
init();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
Child::~Child() {
|
|
|
|
|
|
|
|
|
ChildStream::~ChildStream() {
|
|
|
// Close handles.
|
|
|
// Close handles.
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void
|
|
|
void
|
|
|
Child::init() {
|
|
|
|
|
|
|
|
|
ChildStream::init() {
|
|
|
|
|
|
|
|
|
if (cmdArgs.empty()) {
|
|
|
if (cmdArgs.empty()) {
|
|
|
throw std::invalid_argument("A child executable must be specified.");
|
|
|
throw std::invalid_argument("A child executable must be specified.");
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
size_t
|
|
|
size_t
|
|
|
Child::numBytesAvailable() const {
|
|
|
|
|
|
|
|
|
ChildStream::numBytesAvailable() const {
|
|
|
|
|
|
|
|
|
return childStreambuf.numBytesAvailable();
|
|
|
return childStreambuf.numBytesAvailable();
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void
|
|
|
void
|
|
|
Child::run() {
|
|
|
|
|
|
|
|
|
ChildStream::run() {
|
|
|
|
|
|
|
|
|
if (childStarted) {
|
|
|
if (childStarted) {
|
|
|
throw std::logic_error("Child process was active when "
|
|
|
throw std::logic_error("Child process was active when "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send message to parent.
|
|
|
// Send message to parent.
|
|
|
errMsg = "Error redirecting stdin in the child: " + getErrorText();
|
|
|
errMsg = "Error redirecting stdin in the child: " + getErrorText();
|
|
|
write(childStdOutPipe[1], errMsg.data(), errMsg.size());
|
|
|
|
|
|
|
|
|
::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
|
|
|
exit(-1);
|
|
|
exit(-1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send message to parent.
|
|
|
// Send message to parent.
|
|
|
errMsg = "Error redirecting stdout in the child: " + getErrorText();
|
|
|
errMsg = "Error redirecting stdout in the child: " + getErrorText();
|
|
|
write(childStdOutPipe[1], errMsg.data(), errMsg.size());
|
|
|
|
|
|
|
|
|
::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
|
|
|
exit(-1);
|
|
|
exit(-1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send message to parent.
|
|
|
// Send message to parent.
|
|
|
errMsg = "Error closing the pipes in the child: " + getErrorText();
|
|
|
errMsg = "Error closing the pipes in the child: " + getErrorText();
|
|
|
write(STDOUT_FILENO, errMsg.data(), errMsg.size());
|
|
|
|
|
|
|
|
|
::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
|
|
|
exit(-1);
|
|
|
exit(-1);
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Send message to parent.
|
|
|
// Send message to parent.
|
|
|
errMsg = "Error from exec: " + getErrorText();
|
|
|
errMsg = "Error from exec: " + getErrorText();
|
|
|
write(STDOUT_FILENO, errMsg.data(), errMsg.size());
|
|
|
|
|
|
|
|
|
::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
|
|
|
exit(-1);
|
|
|
exit(-1);
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void
|
|
|
void
|
|
|
Child::terminate() {
|
|
|
|
|
|
|
|
|
ChildStream::terminate() {
|
|
|
|
|
|
|
|
|
if (isDone()) {
|
|
|
if (isDone()) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
bool
|
|
|
bool
|
|
|
Child::isDone() {
|
|
|
|
|
|
|
|
|
ChildStream::isDone() {
|
|
|
|
|
|
|
|
|
if (childExited) {
|
|
|
if (childExited) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
int32_t
|
|
|
int32_t
|
|
|
Child::result() {
|
|
|
|
|
|
|
|
|
ChildStream::result() {
|
|
|
|
|
|
|
|
|
if (exitCodeObtainedFlag) {
|
|
|
if (exitCodeObtainedFlag) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
std::string
|
|
|
std::string
|
|
|
Child::getErrorText() {
|
|
|
|
|
|
|
|
|
ChildStream::getErrorText() {
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#ifdef _WIN32
|
|
|
LPVOID winMsgBuf;
|
|
|
LPVOID winMsgBuf;
|
|
|
|
|
|
|
|
|
#endif
|
|
|
#endif
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
Child::ChildStreambuf::ChildStreambuf(std::size_t bufferSize) :
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::ChildStreambuf(std::size_t bufferSize) :
|
|
|
#ifdef _WIN32
|
|
|
#ifdef _WIN32
|
|
|
inputHandle(0),
|
|
|
inputHandle(0),
|
|
|
outputHandle(0),
|
|
|
outputHandle(0),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#ifdef _WIN32
|
|
|
void
|
|
|
void
|
|
|
Child::ChildStreambuf::setInputHandle(HANDLE inHandle) {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
|
|
|
|
|
|
|
|
|
inputHandle = inHandle;
|
|
|
inputHandle = inHandle;
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
#else
|
|
|
#else
|
|
|
void
|
|
|
void
|
|
|
Child::ChildStreambuf::setInputFileDescriptor(int inFd) {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
|
|
|
|
|
|
|
|
|
inputFileDescriptor = inFd;
|
|
|
inputFileDescriptor = inFd;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
|
|
|
size_t
|
|
|
size_t
|
|
|
Child::ChildStreambuf::numBytesAvailable() const {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::numBytesAvailable() const {
|
|
|
|
|
|
|
|
|
size_t nBytesAvailable = egptr() - gptr();
|
|
|
size_t nBytesAvailable = egptr() - gptr();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
std::streambuf::int_type
|
|
|
std::streambuf::int_type
|
|
|
Child::ChildStreambuf::underflow() {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::underflow() {
|
|
|
|
|
|
|
|
|
// Check for empty buffer.
|
|
|
// Check for empty buffer.
|
|
|
if (gptr() < egptr()) {
|
|
|
if (gptr() < egptr()) {
|
|
|
|
|
|
|
|
|
#else
|
|
|
#else
|
|
|
ssize_t nBytesRead;
|
|
|
ssize_t nBytesRead;
|
|
|
|
|
|
|
|
|
nBytesRead = read(inputFileDescriptor,
|
|
|
|
|
|
start,
|
|
|
|
|
|
readBuffer.size() - (start - base));
|
|
|
|
|
|
|
|
|
nBytesRead = ::read(inputFileDescriptor,
|
|
|
|
|
|
start,
|
|
|
|
|
|
readBuffer.size() - (start - base));
|
|
|
if (-1 == nBytesRead) {
|
|
|
if (-1 == nBytesRead) {
|
|
|
return traits_type::eof();
|
|
|
return traits_type::eof();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
#ifdef _WIN32
|
|
|
void
|
|
|
void
|
|
|
Child::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
|
|
|
|
|
|
|
|
|
outputHandle = outHandle;
|
|
|
outputHandle = outHandle;
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
#else
|
|
|
#else
|
|
|
void
|
|
|
void
|
|
|
Child::ChildStreambuf::setOutputFileDescriptor(int outFd) {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
|
|
|
|
|
|
|
|
|
outputFileDescriptor = outFd;
|
|
|
outputFileDescriptor = outFd;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
|
|
|
void
|
|
|
void
|
|
|
Child::ChildStreambuf::flushBuffer() {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::flushBuffer() {
|
|
|
|
|
|
|
|
|
// Write.
|
|
|
// Write.
|
|
|
std::ptrdiff_t nBytes = pptr() - pbase();
|
|
|
std::ptrdiff_t nBytes = pptr() - pbase();
|
|
|
|
|
|
|
|
|
#else
|
|
|
#else
|
|
|
ssize_t nBytesWritten;
|
|
|
ssize_t nBytesWritten;
|
|
|
|
|
|
|
|
|
nBytesWritten = write(outputFileDescriptor, pbase(), nBytes);
|
|
|
|
|
|
|
|
|
nBytesWritten = ::write(outputFileDescriptor, pbase(), nBytes);
|
|
|
|
|
|
|
|
|
#endif
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
std::streambuf::int_type
|
|
|
std::streambuf::int_type
|
|
|
Child::ChildStreambuf::overflow(int_type ch) {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::overflow(int_type ch) {
|
|
|
|
|
|
|
|
|
// Check whether we're writing EOF.
|
|
|
// Check whether we're writing EOF.
|
|
|
if (traits_type::eof() != ch) {
|
|
|
if (traits_type::eof() != ch) {
|
|
|
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
int
|
|
|
int
|
|
|
Child::ChildStreambuf::sync() {
|
|
|
|
|
|
|
|
|
ChildStream::ChildStreambuf::sync() {
|
|
|
|
|
|
|
|
|
flushBuffer(); // Throws exception on failure.
|
|
|
flushBuffer(); // Throws exception on failure.
|
|
|
|
|
|
|