Procházet zdrojové kódy

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 před 9 roky
rodič
revize
3d82bf14a7
2 změnil soubory, kde provedl 78 přidání a 126 odebrání
  1. 35
    48
      child.cpp
  2. 43
    78
      child.hpp

+ 35
- 48
child.cpp Zobrazit soubor

@@ -33,15 +33,13 @@
#include <stdexcept>
#include "child.hpp"
#include "CodeDweller/child.hpp"
namespace CodeDweller {
Child::Child(std::vector<std::string> args, size_t bufSize) :
readStreambuf(bufSize),
writeStreambuf(bufSize),
reader(&readStreambuf),
writer(&writeStreambuf),
childStreambuf(bufSize),
childStream(&childStreambuf),
cmdArgs(args) {
init();
@@ -49,10 +47,8 @@ namespace CodeDweller {
}
Child::Child(std::string childpath, size_t bufSize) :
readStreambuf(bufSize),
writeStreambuf(bufSize),
reader(&readStreambuf),
writer(&writeStreambuf),
childStreambuf(bufSize),
childStream(&childStreambuf),
cmdline(childpath) {
cmdArgs.push_back(childpath);
init();
@@ -78,7 +74,7 @@ namespace CodeDweller {
size_t
Child::numBytesAvailable() const {
return readStreambuf.numBytesAvailable();
return childStreambuf.numBytesAvailable();
}
@@ -196,8 +192,8 @@ namespace CodeDweller {
// Provide the stream buffers with the handles for communicating
// 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.
childProcess = processInfo.hProcess;
@@ -303,8 +299,8 @@ namespace CodeDweller {
// Provide the stream buffers with the file descriptors for
// 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.
if ( (close(childStdInPipe[0]) != 0) ||
@@ -377,25 +373,21 @@ namespace CodeDweller {
int status = 0;
result = waitpid(childPid, &status, WNOHANG);
// std::cout << "isDone(). waitpid(" << childPid << ",...) returned " << result << std::endl; // DEBUG
if (-1 == result) {
throw std::runtime_error("Error checking status of child process: " +
getErrorText());
} else if (0 == result) {
// Child is still running.
// std::cout << "isDone(). Child is still running..." << std::endl; // DEBUG.
return false;
}
// std::cout << "isDone(). Child exited." << std::endl; // DEBUG.
if (WIFEXITED(status)) {
// Child exited normally.
exitCode = WEXITSTATUS(status);
exitCodeObtainedFlag = true;
//std::cout << "isDone(). Child exited normally. Exit code: " << exitCode << std::endl; // DEBUG.
}
@@ -461,31 +453,41 @@ namespace CodeDweller {
#endif
}
Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
Child::ChildStreambuf::ChildStreambuf(std::size_t bufferSize) :
#ifdef _WIN32
inputHandle(0),
outputHandle(0),
#else
inputFileDescriptor(-1),
outputFileDescriptor(-1),
#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.
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
void
Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
Child::ChildStreambuf::setInputHandle(HANDLE inHandle) {
inputHandle = inHandle;
}
#else
void
Child::ReadStreambuf::setInputFileDescriptor(int inFd) {
Child::ChildStreambuf::setInputFileDescriptor(int inFd) {
inputFileDescriptor = inFd;
@@ -493,7 +495,7 @@ namespace CodeDweller {
#endif
size_t
Child::ReadStreambuf::numBytesAvailable() const {
Child::ChildStreambuf::numBytesAvailable() const {
size_t nBytesAvailable = egptr() - gptr();
@@ -536,7 +538,7 @@ namespace CodeDweller {
}
std::streambuf::int_type
Child::ReadStreambuf::underflow() {
Child::ChildStreambuf::underflow() {
// Check for empty buffer.
if (gptr() < egptr()) {
@@ -547,7 +549,7 @@ namespace CodeDweller {
}
// Need to fill the buffer.
char *base = &(buffer.front());
char *base = &(readBuffer.front());
char *start = base;
// Check whether this is the first fill.
@@ -564,7 +566,7 @@ namespace CodeDweller {
if (!ReadFile(inputHandle,
start,
buffer.size() - (start - base),
readBuffer.size() - (start - base),
&nBytesRead,
NULL)) {
return traits_type::eof();
@@ -574,7 +576,7 @@ namespace CodeDweller {
nBytesRead = read(inputFileDescriptor,
start,
buffer.size() - (start - base));
readBuffer.size() - (start - base));
if (-1 == nBytesRead) {
return traits_type::eof();
}
@@ -592,31 +594,16 @@ namespace CodeDweller {
}
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
void
Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
Child::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
outputHandle = outHandle;
}
#else
void
Child::WriteStreambuf::setOutputFileDescriptor(int outFd) {
Child::ChildStreambuf::setOutputFileDescriptor(int outFd) {
outputFileDescriptor = outFd;
@@ -624,7 +611,7 @@ namespace CodeDweller {
#endif
void
Child::WriteStreambuf::flushBuffer() {
Child::ChildStreambuf::flushBuffer() {
// Write.
std::ptrdiff_t nBytes = pptr() - pbase();
@@ -662,7 +649,7 @@ namespace CodeDweller {
}
std::streambuf::int_type
Child::WriteStreambuf::overflow(int_type ch) {
Child::ChildStreambuf::overflow(int_type ch) {
// Check whether we're writing EOF.
if (traits_type::eof() != ch) {
@@ -684,7 +671,7 @@ namespace CodeDweller {
}
int
Child::WriteStreambuf::sync() {
Child::ChildStreambuf::sync() {
flushBuffer(); // Throws exception on failure.

+ 43
- 78
child.hpp Zobrazit soubor

@@ -34,8 +34,7 @@

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

@@ -61,22 +60,23 @@ namespace CodeDweller {

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;

public:

/// Reader streambuf constructor.
/// Constructor.
//
// \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

/// Set the handle to read the standard output of the child
/// process.
//
@@ -84,7 +84,17 @@ namespace CodeDweller {
// output of the child process.
//
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

/// Set the file descriptor to read the standard output of the
/// child process.
//
@@ -92,6 +102,15 @@ namespace CodeDweller {
// output of the child process.
//
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

private:
@@ -113,61 +132,6 @@ namespace CodeDweller {
/// Override streambuf::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.
void flushBuffer();

@@ -178,28 +142,31 @@ namespace CodeDweller {
int sync();

/// 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
HANDLE inputHandle;
HANDLE outputHandle;
#else
int inputFileDescriptor;
int outputFileDescriptor;
#endif

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

/// 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:

@@ -235,8 +202,9 @@ namespace CodeDweller {
/** Destructor terminates the child process. */
~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.

@@ -246,9 +214,6 @@ namespace CodeDweller {
*/
size_t numBytesAvailable() const;

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

/** Spawn the child process.

\throws runtime_error if an error occurs.

Načítá se…
Zrušit
Uložit