Browse Source

ChildStream inherits from std::iostream.


git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@77 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 9 years ago
parent
commit
669f79a111
2 changed files with 41 additions and 46 deletions
  1. 30
    30
      child.cpp
  2. 11
    16
      child.hpp

+ 30
- 30
child.cpp View File

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.

+ 11
- 16
child.hpp View File



*/ */


/** Class that abstracts the creation of child processes.
/** Class that abstracts the communication with a child process.


This class provides functionality to create a child process, This class provides functionality to create a child process,
communicate with the child process via streams and signals, and communicate with the child process via streams and signals, and


*/ */


class Child {
class ChildStream : public std::iostream {


private: private:


/// writing to the standard input of the child process. /// writing to the standard input of the child process.
class ChildStreambuf : public std::streambuf { class ChildStreambuf : public std::streambuf {


friend class Child;
friend class ChildStream;


public: public:


executable, and args[1] thru args[n] are the command-line executable, and args[1] thru args[n] are the command-line
parameters. parameters.


\param[in] bufSize is the buffer size of the reader and writer
streams used to communicate with the child process.
\param[in] bufSize is the input and output buffer size of the
stream used to communicate with the child process.


*/ */
Child(std::vector<std::string> args, size_t bufSize = 4096);
ChildStream(std::vector<std::string> args, size_t bufSize = 4096);


/** Constructor for spawning without command-line parameters. /** Constructor for spawning without command-line parameters.




\param[in] childpath contains the child executable file name. \param[in] childpath contains the child executable file name.


\param[in] bufSize is the buffer size of the reader and writer
streams used to communicate with the child process.
\param[in] bufSize is the input and output buffer size of the
stream used to communicate with the child process.


*/ */
Child(std::string childpath, size_t bufSize = 4096);
ChildStream(std::string childpath, size_t bufSize = 4096);


/** Destructor terminates the child process. */ /** Destructor terminates the child process. */
~Child();

/// I/O stream to read data from the child's standard output and
/// write data to the child's standard input.
std::iostream childStream;
~ChildStream();


/** Get the number of bytes available for input. /** Get the number of bytes available for input.


@returns number of bytes that can be read from reader without
blocking.
@returns number of bytes that can be read without blocking.


*/ */
size_t numBytesAvailable() const; size_t numBytesAvailable() const;

Loading…
Cancel
Save