Browse Source

Merged input and output streambuf.


git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@76 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 9 years ago
parent
commit
3d82bf14a7
2 changed files with 78 additions and 126 deletions
  1. 35
    48
      child.cpp
  2. 43
    78
      child.hpp

+ 35
- 48
child.cpp View File

#include <stdexcept> #include <stdexcept>
#include "child.hpp"
#include "CodeDweller/child.hpp"
namespace CodeDweller { namespace CodeDweller {
Child::Child(std::vector<std::string> args, size_t bufSize) : Child::Child(std::vector<std::string> args, size_t bufSize) :
readStreambuf(bufSize),
writeStreambuf(bufSize),
reader(&readStreambuf),
writer(&writeStreambuf),
childStreambuf(bufSize),
childStream(&childStreambuf),
cmdArgs(args) { cmdArgs(args) {
init(); init();
} }
Child::Child(std::string childpath, size_t bufSize) : Child::Child(std::string childpath, size_t bufSize) :
readStreambuf(bufSize),
writeStreambuf(bufSize),
reader(&readStreambuf),
writer(&writeStreambuf),
childStreambuf(bufSize),
childStream(&childStreambuf),
cmdline(childpath) { cmdline(childpath) {
cmdArgs.push_back(childpath); cmdArgs.push_back(childpath);
init(); init();
size_t size_t
Child::numBytesAvailable() const { Child::numBytesAvailable() const {
return readStreambuf.numBytesAvailable();
return childStreambuf.numBytesAvailable();
} }
// Provide the stream buffers with the handles for communicating // Provide the stream buffers with the handles for communicating
// with the child process. // with the child process.
readStreambuf.setInputHandle(childStdOutAtParent);
writeStreambuf.setOutputHandle(childStdInAtParent);
childStreambuf.setInputHandle(childStdOutAtParent);
childStreambuf.setOutputHandle(childStdInAtParent);
// Save the handles to the child process and its primary thread. // Save the handles to the child process and its primary thread.
childProcess = processInfo.hProcess; childProcess = processInfo.hProcess;
// Provide the stream buffers with the file descriptors for // Provide the stream buffers with the file descriptors for
// communicating with the child process. // communicating with the child process.
readStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
writeStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
childStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
childStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
// Close the child's end of the pipes. // Close the child's end of the pipes.
if ( (close(childStdInPipe[0]) != 0) || if ( (close(childStdInPipe[0]) != 0) ||
int status = 0; int status = 0;
result = waitpid(childPid, &status, WNOHANG); result = waitpid(childPid, &status, WNOHANG);
// std::cout << "isDone(). waitpid(" << childPid << ",...) returned " << result << std::endl; // DEBUG
if (-1 == result) { if (-1 == result) {
throw std::runtime_error("Error checking status of child process: " + throw std::runtime_error("Error checking status of child process: " +
getErrorText()); getErrorText());
} else if (0 == result) { } else if (0 == result) {
// Child is still running. // Child is still running.
// std::cout << "isDone(). Child is still running..." << std::endl; // DEBUG.
return false; return false;
} }
// std::cout << "isDone(). Child exited." << std::endl; // DEBUG.
if (WIFEXITED(status)) { if (WIFEXITED(status)) {
// Child exited normally. // Child exited normally.
exitCode = WEXITSTATUS(status); exitCode = WEXITSTATUS(status);
exitCodeObtainedFlag = true; exitCodeObtainedFlag = true;
//std::cout << "isDone(). Child exited normally. Exit code: " << exitCode << std::endl; // DEBUG.
} }
#endif #endif
} }
Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
Child::ChildStreambuf::ChildStreambuf(std::size_t bufferSize) :
#ifdef _WIN32 #ifdef _WIN32
inputHandle(0), inputHandle(0),
outputHandle(0),
#else #else
inputFileDescriptor(-1), inputFileDescriptor(-1),
outputFileDescriptor(-1),
#endif #endif
buffer(bufferSize + 1) {
readBuffer(bufferSize + 1),
writeBuffer(bufferSize + 1) {
char *end = &(buffer.front()) + buffer.size();
// Read buffer initialization.
char *end = &(readBuffer.front()) + readBuffer.size();
// Indicate to underflow that underflow has not been called. // Indicate to underflow that underflow has not been called.
setg(end, end, end); setg(end, end, end);
// Write buffer initialization.
char *base = &(writeBuffer.front());
// Indicate to overflow that overflow has not been called.
setp(base, base + writeBuffer.size() - 1);
} }
#ifdef _WIN32 #ifdef _WIN32
void void
Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
Child::ChildStreambuf::setInputHandle(HANDLE inHandle) {
inputHandle = inHandle; inputHandle = inHandle;
} }
#else #else
void void
Child::ReadStreambuf::setInputFileDescriptor(int inFd) {
Child::ChildStreambuf::setInputFileDescriptor(int inFd) {
inputFileDescriptor = inFd; inputFileDescriptor = inFd;
#endif #endif
size_t size_t
Child::ReadStreambuf::numBytesAvailable() const {
Child::ChildStreambuf::numBytesAvailable() const {
size_t nBytesAvailable = egptr() - gptr(); size_t nBytesAvailable = egptr() - gptr();
} }
std::streambuf::int_type std::streambuf::int_type
Child::ReadStreambuf::underflow() {
Child::ChildStreambuf::underflow() {
// Check for empty buffer. // Check for empty buffer.
if (gptr() < egptr()) { if (gptr() < egptr()) {
} }
// Need to fill the buffer. // Need to fill the buffer.
char *base = &(buffer.front());
char *base = &(readBuffer.front());
char *start = base; char *start = base;
// Check whether this is the first fill. // Check whether this is the first fill.
if (!ReadFile(inputHandle, if (!ReadFile(inputHandle,
start, start,
buffer.size() - (start - base),
readBuffer.size() - (start - base),
&nBytesRead, &nBytesRead,
NULL)) { NULL)) {
return traits_type::eof(); return traits_type::eof();
nBytesRead = read(inputFileDescriptor, nBytesRead = read(inputFileDescriptor,
start, start,
buffer.size() - (start - base));
readBuffer.size() - (start - base));
if (-1 == nBytesRead) { if (-1 == nBytesRead) {
return traits_type::eof(); return traits_type::eof();
} }
} }
Child::WriteStreambuf::WriteStreambuf(std::size_t bufferSize) :
#ifdef _WIN32
outputHandle(0),
#else
outputFileDescriptor(-1),
#endif
buffer(bufferSize + 1) {
char *base = &(buffer.front());
// Indicate to overflow that overflow has not been called.
setp(base, base + buffer.size() - 1);
}
#ifdef _WIN32 #ifdef _WIN32
void void
Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
Child::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
outputHandle = outHandle; outputHandle = outHandle;
} }
#else #else
void void
Child::WriteStreambuf::setOutputFileDescriptor(int outFd) {
Child::ChildStreambuf::setOutputFileDescriptor(int outFd) {
outputFileDescriptor = outFd; outputFileDescriptor = outFd;
#endif #endif
void void
Child::WriteStreambuf::flushBuffer() {
Child::ChildStreambuf::flushBuffer() {
// Write. // Write.
std::ptrdiff_t nBytes = pptr() - pbase(); std::ptrdiff_t nBytes = pptr() - pbase();
} }
std::streambuf::int_type std::streambuf::int_type
Child::WriteStreambuf::overflow(int_type ch) {
Child::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::WriteStreambuf::sync() {
Child::ChildStreambuf::sync() {
flushBuffer(); // Throws exception on failure. flushBuffer(); // Throws exception on failure.

+ 43
- 78
child.hpp View File



#include <cstdint> #include <cstdint>
#include <streambuf> #include <streambuf>
#include <istream>
#include <ostream>
#include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>




private: private:


/// Streambuf class for reading the standard output of the child
/// process.
class ReadStreambuf : public std::streambuf {
/// Streambuf class for reading from the standard output and
/// writing to the standard input of the child process.
class ChildStreambuf : public std::streambuf {


friend class Child; friend class Child;


public: public:


/// Reader streambuf constructor.
/// Constructor.
// //
// \param[in] bufferSize is the size in bytes of the input // \param[in] bufferSize is the size in bytes of the input
// buffer.
// buffer and output buffer.
// //
explicit ReadStreambuf(std::size_t bufferSize = 4096);
explicit ChildStreambuf(std::size_t bufferSize = 4096);


#ifdef _WIN32 #ifdef _WIN32

/// Set the handle to read the standard output of the child /// Set the handle to read the standard output of the child
/// process. /// process.
// //
// output of the child process. // output of the child process.
// //
void setInputHandle(HANDLE inHandle); void setInputHandle(HANDLE inHandle);

/// Set the handle to write the standard input of the child
/// process.
//
// \param[in] outHandle is the output handle for the standard
// input of the child process.
//
void setOutputHandle(HANDLE outHandle);

#else #else

/// Set the file descriptor to read the standard output of the /// Set the file descriptor to read the standard output of the
/// child process. /// child process.
// //
// output of the child process. // output of the child process.
// //
void setInputFileDescriptor(int inFd); void setInputFileDescriptor(int inFd);

/// Set the file descriptor to write the standard input of the
/// child process.
//
// \param[in] outFd is the output file descriptor for the
// standard input of the child process.
//
void setOutputFileDescriptor(int outFd);

#endif #endif


private: private:
/// Override streambuf::underflow(). /// Override streambuf::underflow().
int_type underflow(); int_type underflow();


/// Copy constructor not implemented.
ReadStreambuf(const ReadStreambuf &);

/// Copy constructor not implemented.
ReadStreambuf &operator=(const ReadStreambuf &);

/// Input handle.
#ifdef _WIN32
HANDLE inputHandle;
#else
int inputFileDescriptor;
#endif

/// Read buffer.
std::vector<char> buffer;

};

/// Streambuf class for writing to the standard input of the child
/// process.
//
// Note: If an error occurs when writing the output from the
// parent process, the output buffer is cleared.
//
class WriteStreambuf : public std::streambuf {

public:

/// Writer streambuf constructor.
//
// \param[in] bufferSize is the size in bytes of the input
// buffer.
//
explicit WriteStreambuf(std::size_t bufferSize = 4096);

#ifdef _WIN32
/// Set the handle to write the standard input of the child
/// process.
//
// \param[in] outHandle is the output handle for the standard
// input of the child process.
//
void setOutputHandle(HANDLE outHandle);
#else
/// Set the file descriptor to write the standard input of the
/// child process.
//
// \param[in] outFd is the output file descriptor for the
// standard input of the child process.
//
void setOutputFileDescriptor(int outFd);
#endif

private:

/// Flush the output buffer. /// Flush the output buffer.
void flushBuffer(); void flushBuffer();


int sync(); int sync();


/// Copy constructor not implemented. /// Copy constructor not implemented.
WriteStreambuf(const WriteStreambuf &);
ChildStreambuf(const ChildStreambuf &) = delete;


/// Copy constructor not implemented.
WriteStreambuf &operator=(const WriteStreambuf &);
/// Assignment operator not implemented.
ChildStreambuf &operator=(const ChildStreambuf &) = delete;


/// Output handle.
/// Input and output handles.
#ifdef _WIN32 #ifdef _WIN32
HANDLE inputHandle;
HANDLE outputHandle; HANDLE outputHandle;
#else #else
int inputFileDescriptor;
int outputFileDescriptor; int outputFileDescriptor;
#endif #endif


/// Read buffer.
std::vector<char> readBuffer;

/// Write buffer. /// Write buffer.
std::vector<char> buffer;
std::vector<char> writeBuffer;


}; };


/// Stream buffer for reading from the stdout of the child process;
ReadStreambuf readStreambuf;

/// Stream buffer for writing to the stdin of the child process;
WriteStreambuf writeStreambuf;
/// Stream buffer for reading from the stdout and writing to the
/// stdin of the child process.
ChildStreambuf childStreambuf;


public: public:


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


/// Input stream to read data from the child's standard output.
std::istream reader;
/// I/O stream to read data from the child's standard output and
/// write data to the child's standard input.
std::iostream childStream;


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


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


/// Output stream to write data to the child's standard input.
std::ostream writer;

/** Spawn the child process. /** Spawn the child process.


\throws runtime_error if an error occurs. \throws runtime_error if an error occurs.

Loading…
Cancel
Save