Browse Source

Completed unit tests on Windows.

git-svn-id: https://svn.microneil.com/svn/CodeDweller/branches/adeniz_1@32 d34b734f-a00e-4b39-a726-e4eeb87269ab
adeniz_1
adeniz 10 years ago
parent
commit
6fc2c7c921
1 changed files with 192 additions and 183 deletions
  1. 192
    183
      child.cpp

+ 192
- 183
child.cpp View File

@@ -63,6 +63,8 @@ namespace CodeDweller {
void
Child::init() {
reader.exceptions(std::istream::failbit | std::istream::badbit);
writer.exceptions(std::ostream::failbit | std::ostream::badbit);
childStarted = false;
exitCodeObtainedFlag = false;
exitCode = 0;
@@ -77,112 +79,112 @@ namespace CodeDweller {
}
// Set the bInheritHandle flag so pipe handles are inherited.
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = true;
securityAttributes.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
HANDLE childStdOutAtChild;
HANDLE childStdOutAtParent;
HANDLE childStdInAtChild;
HANDLE childStdInAtParent;
int bufferSize = 0;
if (!CreatePipe(&childStdOutAtParent,
&childStdOutAtChild,
&securityAttributes,
bufferSize)) {
throw std::runtime_error("Error from CreatePipe for stdout: " +
getErrorText());
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
int inheritFlag = 0;
if (!SetHandleInformation(childStdOutAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag) ) {
throw std::runtime_error("Error from GetHandleInformation for stdout: " +
getErrorText());
}
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&childStdInAtChild,
&childStdInAtParent,
SECURITY_ATTRIBUTES securityAttributes;
securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttributes.bInheritHandle = true;
securityAttributes.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
HANDLE childStdOutAtChild;
HANDLE childStdOutAtParent;
HANDLE childStdInAtChild;
HANDLE childStdInAtParent;
int bufferSize = 0;
if (!CreatePipe(&childStdOutAtParent,
&childStdOutAtChild,
&securityAttributes,
bufferSize)) {
throw std::runtime_error("Error from CreatePipe for stdin: " +
getErrorText());
}
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(childStdInAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag)) {
throw std::runtime_error("Error from GetHandleInformation for stdin: " +
getErrorText());
}
throw std::runtime_error("Error from CreatePipe for stdout: " +
getErrorText());
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
int inheritFlag = 0;
if (!SetHandleInformation(childStdOutAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag) ) {
throw std::runtime_error("Error from GetHandleInformation for stdout: " +
getErrorText());
}
// Create a pipe for the child process's STDIN.
if (! CreatePipe(&childStdInAtChild,
&childStdInAtParent,
&securityAttributes,
bufferSize)) {
throw std::runtime_error("Error from CreatePipe for stdin: " +
getErrorText());
}
// Ensure the write handle to the pipe for STDIN is not inherited.
if (!SetHandleInformation(childStdInAtParent,
HANDLE_FLAG_INHERIT,
inheritFlag)) {
throw std::runtime_error("Error from GetHandleInformation for stdin: " +
getErrorText());
}
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION processInfo;
// Set up members of the PROCESS_INFORMATION structure.
PROCESS_INFORMATION processInfo;
std::fill((char *) &processInfo,
((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
0);
std::fill((char *) &processInfo,
((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
0);
// Set up members of the STARTUPINFO structure. This structure
// specifies the STDIN and STDOUT handles for redirection.
STARTUPINFO startInfo;
std::fill((char *) &startInfo,
((char *) &startInfo) + sizeof(STARTUPINFO),
0);
startInfo.cb = sizeof(STARTUPINFO);
startInfo.hStdError = childStdOutAtChild;
startInfo.hStdOutput = childStdOutAtChild;
startInfo.hStdInput = childStdInAtChild;
startInfo.dwFlags |= STARTF_USESTDHANDLES;
// Set up members of the STARTUPINFO structure. This structure
// specifies the STDIN and STDOUT handles for redirection.
STARTUPINFO startInfo;
std::fill((char *) &startInfo,
((char *) &startInfo) + sizeof(STARTUPINFO),
0);
startInfo.cb = sizeof(STARTUPINFO);
startInfo.hStdError = childStdOutAtChild;
startInfo.hStdOutput = childStdOutAtChild;
startInfo.hStdInput = childStdInAtChild;
startInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bool status;
// Create the child process.
bool status;
status = CreateProcess(NULL,
(char *) cmdline.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
true, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&startInfo, // STARTUPINFO pointer
&processInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!status ) {
throw std::runtime_error("Error from CreateProcess with "
"command line \"" + cmdline + "\": " +
getErrorText());
}
// Provide the stream buffers with the handles for communicating
// with the child process.
readStreambuf.setInputHandle(childStdOutAtParent);
writeStreambuf.setOutputHandle(childStdInAtParent);
// Save the handles to the child process and its primary thread.
childProcess = processInfo.hProcess;
childThread = processInfo.hThread;
childStarted = true;
// Close the child's end of the pipes.
if (!CloseHandle(childStdOutAtChild)) {
status = CreateProcess(NULL,
(char *) cmdline.c_str(), // command line
NULL, // process security attributes
NULL, // primary thread security attributes
true, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&startInfo, // STARTUPINFO pointer
&processInfo); // receives PROCESS_INFORMATION
// If an error occurs, exit the application.
if (!status ) {
throw std::runtime_error("Error from CreateProcess with "
"command line \"" + cmdline + "\": " +
getErrorText());
}
// Provide the stream buffers with the handles for communicating
// with the child process.
readStreambuf.setInputHandle(childStdOutAtParent);
writeStreambuf.setOutputHandle(childStdInAtParent);
// Save the handles to the child process and its primary thread.
childProcess = processInfo.hProcess;
childThread = processInfo.hThread;
childStarted = true;
// Close the child's end of the pipes.
if (!CloseHandle(childStdOutAtChild)) {
throw std::runtime_error("Error closing the child process stdout handle: " +
getErrorText());
}
if (!CloseHandle(childStdInAtChild)) {
if (!CloseHandle(childStdInAtChild)) {
throw std::runtime_error("Error closing the child process stdin handle: " +
getErrorText());
}
@@ -199,38 +201,38 @@ namespace CodeDweller {
}
if (!TerminateProcess(childProcess, terminateExitCode)) {
throw std::runtime_error("Error terminating the child process: " +
getErrorText());
}
throw std::runtime_error("Error terminating the child process: " +
getErrorText());
}
}
bool
Child::isDone() {
bool
Child::isDone() {
if (exitCodeObtainedFlag) {
return true;
return true;
}
}
if (!childStarted) {
throw std::logic_error("Child process was not started "
"when isDone() was called");
}
throw std::logic_error("Child process was not started "
"when isDone() was called");
}
int result;
if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
throw std::runtime_error("Error checking status of child process: " +
getErrorText());
}
throw std::runtime_error("Error checking status of child process: " +
getErrorText());
}
if (STILL_ACTIVE == result) {
return false;
return false;
}
}
// Child process has exited. Save the exit code.
exitCode = result;
@@ -240,32 +242,32 @@ namespace CodeDweller {
}
int32_t
Child::result() {
int32_t
Child::result() {
if (exitCodeObtainedFlag) {
return exitCode;
return exitCode;
}
}
if (!childStarted) {
throw std::logic_error("Child process was not started "
"when result() was called");
}
throw std::logic_error("Child process was not started "
"when result() was called");
}
int result;
if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
throw std::runtime_error("Error getting child process exit code: " +
getErrorText());
}
throw std::runtime_error("Error getting child process exit code: " +
getErrorText());
}
// Error if the process has not exited.
if (STILL_ACTIVE == result) {
throw std::logic_error("Child process was active when "
"result() was called");
}
throw std::logic_error("Child process was active when "
"result() was called");
}
// Child process has exited. Save the exit code.
exitCode = result;
@@ -274,21 +276,21 @@ namespace CodeDweller {
return result;
}
std::string
Child::getErrorText() {
std::string
Child::getErrorText() {
LPVOID winMsgBuf;
DWORD lastError = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &winMsgBuf,
0, NULL );
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(char *) &winMsgBuf,
0, NULL );
std::string errMsg((char *) winMsgBuf);
@@ -296,9 +298,9 @@ namespace CodeDweller {
return errMsg;
}
Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
inputHandle(0),
buffer(bufferSize + 1) {
Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
inputHandle(0),
buffer(bufferSize + 1) {
char *end = &(buffer.front()) + buffer.size();
@@ -307,23 +309,23 @@ namespace CodeDweller {
}
void
Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
void
Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
inputHandle = inHandle;
}
std::streambuf::int_type
Child::ReadStreambuf::underflow() {
std::streambuf::int_type
Child::ReadStreambuf::underflow() {
// Check for empty buffer.
if (gptr() < egptr()) {
// Not empty.
return traits_type::to_int_type(*gptr());
// Not empty.
return traits_type::to_int_type(*gptr());
}
}
// Need to fill the buffer.
char *base = &(buffer.front());
@@ -332,25 +334,26 @@ namespace CodeDweller {
// Check whether this is the first fill.
if (eback() == base) {
// Not the first fill. Copy putback characters.
}
// Not the first fill. Copy one putback character.
*(eback()) = *(egptr() - 1);
start++;
}
// start points to the start of the buffer. Fill buffer.
DWORD nBytesRead;
if (!ReadFile(inputHandle,
start,
buffer.size() - (start - base),
&nBytesRead,
NULL)) {
return traits_type::eof();
}
start,
buffer.size() - (start - base),
&nBytesRead,
NULL)) {
return traits_type::eof();
}
// Check for EOF.
if (0 == nBytesRead) {
return traits_type::eof();
}
return traits_type::eof();
}
// Update buffer pointers.
setg(base, start, start + nBytesRead);
@@ -359,9 +362,9 @@ namespace CodeDweller {
}
Child::WriteStreambuf::WriteStreambuf(std::size_t bufferSize) :
outputHandle(0),
buffer(bufferSize + 1) {
Child::WriteStreambuf::WriteStreambuf(std::size_t bufferSize) :
outputHandle(0),
buffer(bufferSize + 1) {
char *base = &(buffer.front());
@@ -370,63 +373,69 @@ namespace CodeDweller {
}
void
Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
void
Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
outputHandle = outHandle;
}
void
Child::WriteStreambuf::flushBuffer() {
void
Child::WriteStreambuf::flushBuffer() {
// Write.
std::ptrdiff_t nBytes = pptr() - pbase();
DWORD nBytesWritten;
if (!WriteFile(outputHandle,
pbase(),
nBytes,
&nBytesWritten,
NULL)) {
throw std::runtime_error("Error writing to child process: " +
getErrorText());
}
pbase(),
nBytes,
&nBytesWritten,
NULL)) {
pbump(epptr() - pptr()); // Indicate failure.
throw std::runtime_error("Error writing to child process: " +
getErrorText());
}
if (nBytes != nBytesWritten) {
throw std::runtime_error("Not all data was written to to child process: " +
getErrorText());
}
pbump(epptr() - pptr()); // Indicate failure.
throw std::runtime_error("Not all data was written to to child process: " +
getErrorText());
}
pbump(-nBytes);
return;
}
std::streambuf::int_type
Child::WriteStreambuf::overflow(int_type ch) {
std::streambuf::int_type
Child::WriteStreambuf::overflow(int_type ch) {
// Check whether we're writing EOF.
if (traits_type::eof() != ch) {
// Not writing EOF.
*(pptr()) = ch;
pbump(1);
}
// Not writing EOF.
*(pptr()) = ch;
pbump(1);
// Write.
flushBuffer();
// Success.
return traits_type::not_eof('a');
return ch;
}
int
Child::WriteStreambuf::sync() {
return traits_type::eof();
flushBuffer();
return 1; // Success.
}
int
Child::WriteStreambuf::sync() {
flushBuffer(); // Throws exception on failure.
// Success.
return 1;
}

Loading…
Cancel
Save