Index: src/OFProcess.h ================================================================== --- src/OFProcess.h +++ src/OFProcess.h @@ -12,21 +12,31 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#include +#ifndef _WIN32 +# include +#endif #import "OFStream.h" + +#ifdef _WIN32 +# include +#endif /** * \brief A class for stream-like communication with a newly created process. */ @interface OFProcess: OFStream { +#ifndef _WIN32 pid_t pid; int readPipe[2], writePipe[2]; +#else + HANDLE readPipe[2], writePipe[2]; +#endif int status; BOOL atEndOfStream; } /** Index: src/OFProcess.m ================================================================== --- src/OFProcess.m +++ src/OFProcess.m @@ -15,21 +15,28 @@ */ #include "config.h" #include -#include -#include +#ifndef _WIN32 +# include +# include +#endif #import "OFProcess.h" #import "OFString.h" #import "OFArray.h" +#import "OFAutoreleasePool.h" #import "OFInitializationFailedException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" + +#ifdef _WIN32 +# include +#endif @implementation OFProcess + processWithProgram: (OFString*)program { return [[[self alloc] initWithProgram: program] autorelease]; @@ -71,10 +78,11 @@ arguments: (OFArray*)arguments { self = [super init]; @try { +#ifndef _WIN32 if (pipe(readPipe) != 0 || pipe(writePipe) != 0) @throw [OFInitializationFailedException exceptionWithClass: isa]; switch ((pid = fork())) { @@ -108,10 +116,105 @@ default: close(readPipe[1]); close(writePipe[0]); break; } +#else + SECURITY_ATTRIBUTES sa; + PROCESS_INFORMATION pi; + STARTUPINFO si; + OFAutoreleasePool *pool; + OFMutableString *argumentsString; + OFEnumerator *enumerator; + OFString *argument; + char *argumentsCString; + + sa.nLength = sizeof(sa); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&readPipe[0], &readPipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: isa]; + + if (!SetHandleInformation(readPipe[0], HANDLE_FLAG_INHERIT, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: isa]; + + if (!CreatePipe(&writePipe[0], &writePipe[1], &sa, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: isa]; + + if (!SetHandleInformation(writePipe[1], HANDLE_FLAG_INHERIT, 0)) + @throw [OFInitializationFailedException + exceptionWithClass: isa]; + + memset(&pi, 0, sizeof(pi)); + memset(&si, 0, sizeof(si)); + + si.cb = sizeof(si); + si.hStdInput = writePipe[0]; + si.hStdOutput = readPipe[1]; + si.hStdError = GetStdHandle(STD_ERROR_HANDLE); + si.dwFlags |= STARTF_USESTDHANDLES; + + pool = [[OFAutoreleasePool alloc] init]; + + argumentsString = + [OFMutableString stringWithString: programName]; + [argumentsString replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [argumentsString replaceOccurrencesOfString: @"\"" + withString: @"\\\""]; + + if ([argumentsString containsString: @" "]) { + [argumentsString prependString: @"\""]; + [argumentsString appendString: @"\""]; + } + + enumerator = [arguments objectEnumerator]; + while ((argument = [enumerator nextObject]) != nil) { + OFMutableString *tmp = + [[argument mutableCopy] autorelease]; + BOOL containsSpaces = [tmp containsString: @" "]; + + [argumentsString appendString: @" "]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + + [tmp replaceOccurrencesOfString: @"\\\"" + withString: @"\\\\\""]; + [tmp replaceOccurrencesOfString: @"\"" + withString: @"\\\""];; + + [argumentsString appendString: tmp]; + + if (containsSpaces) + [argumentsString appendString: @"\""]; + } + + argumentsCString = strdup([argumentsString + cStringWithEncoding: OF_STRING_ENCODING_NATIVE]); + @try { + if (!CreateProcess([program cStringWithEncoding: + OF_STRING_ENCODING_NATIVE], argumentsCString, NULL, + NULL, TRUE, 0, NULL, NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: isa]; + } @finally { + free(argumentsString); + } + + [pool release]; + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + CloseHandle(readPipe[1]); + CloseHandle(writePipe[0]); +#endif } @catch (id e) { [self release]; @throw e; } @@ -118,26 +221,45 @@ return self; } - (BOOL)_isAtEndOfStream { +#ifndef _WIN32 if (readPipe[0] == -1) +#else + if (readPipe[0] == NULL) +#endif return YES; return atEndOfStream; } - (size_t)_readNBytes: (size_t)length intoBuffer: (void*)buffer { +#ifndef _WIN32 ssize_t ret; +#else + DWORD ret; +#endif +#ifndef _WIN32 if (readPipe[0] == -1 || atEndOfStream || - (ret = read(readPipe[0], buffer, length)) < 0) + (ret = read(readPipe[0], buffer, length)) < 0) { +#else + if (readPipe[0] == NULL || atEndOfStream || + !ReadFile(readPipe[0], buffer, length, &ret, NULL)) { + if (GetLastError() == ERROR_BROKEN_PIPE) { + atEndOfStream = YES; + return 0; + } + +#endif @throw [OFReadFailedException exceptionWithClass: isa stream: self requestedLength: length]; + } if (ret == 0) atEndOfStream = YES; return ret; @@ -144,12 +266,20 @@ } - (void)_writeNBytes: (size_t)length fromBuffer: (const void*)buffer { +#ifndef _WIN32 if (writePipe[1] == -1 || atEndOfStream || write(writePipe[1], buffer, length) < length) +#else + DWORD ret; + + if (writePipe[1] == NULL || atEndOfStream || + !WriteFile(writePipe[1], buffer, length, &ret, NULL) || + ret < length) +#endif @throw [OFWriteFailedException exceptionWithClass: isa stream: self requestedLength: length]; } @@ -166,18 +296,26 @@ * FD for reading and one for writing. */ - (void)closeForWriting { +#ifndef _WIN32 if (writePipe[1] != -1) close(writePipe[1]); writePipe[1] = -1; +#else + if (writePipe[1] != NULL) + CloseHandle(writePipe[1]); + + writePipe[1] = NULL; +#endif } - (void)close { +#ifndef _WIN32 if (readPipe[0] != -1) close(readPipe[0]); if (writePipe[1] != -1) close(writePipe[1]); @@ -185,7 +323,16 @@ waitpid(pid, &status, WNOHANG); pid = -1; readPipe[0] = -1; writePipe[1] = -1; +#else + if (readPipe[0] != NULL) + CloseHandle(readPipe[0]); + if (writePipe[1] != NULL) + CloseHandle(writePipe[1]); + + readPipe[0] = NULL; + writePipe[1] = NULL; +#endif } @end