@@ -19,14 +19,16 @@ #include #include #import "OFProcess.h" -#import "OFString.h" #import "OFArray.h" +#import "OFData.h" #import "OFDictionary.h" -#import "OFData.h" +#import "OFLocale.h" +#import "OFString.h" +#import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #import "OFNotOpenException.h" #import "OFOutOfRangeException.h" #import "OFReadFailedException.h" @@ -33,11 +35,12 @@ #import "OFWriteFailedException.h" #include @interface OFProcess () -- (of_char16_t *)of_environmentForDictionary: (OFDictionary *)dictionary; +- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)dictionary; +- (char *)of_environmentForDictionary: (OFDictionary *)environment; @end @implementation OFProcess + (instancetype)processWithProgram: (OFString *)program { @@ -111,15 +114,12 @@ self = [super init]; @try { SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; - STARTUPINFOW si; void *pool; OFMutableString *argumentsString; - of_char16_t *argumentsCopy; - size_t length; _process = INVALID_HANDLE_VALUE; _readPipe[0] = _writePipe[1] = NULL; sa.nLength = sizeof(sa); @@ -129,30 +129,25 @@ if (!CreatePipe(&_readPipe[0], &_readPipe[1], &sa, 0)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; if (!SetHandleInformation(_readPipe[0], HANDLE_FLAG_INHERIT, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; if (!CreatePipe(&_writePipe[0], &_writePipe[1], &sa, 0)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; if (!SetHandleInformation(_writePipe[1], HANDLE_FLAG_INHERIT, 0)) - @throw [OFInitializationFailedException - exceptionWithClass: self.class]; + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; 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 = objc_autoreleasePoolPush(); argumentsString = [OFMutableString stringWithString: programName]; @@ -185,25 +180,57 @@ if (containsSpaces) [argumentsString appendString: @"\""]; } - length = argumentsString.UTF16StringLength; - argumentsCopy = [self allocMemoryWithSize: sizeof(of_char16_t) - count: length + 1]; - memcpy(argumentsCopy, argumentsString.UTF16String, - (argumentsString.UTF16StringLength + 1) * 2); - @try { - if (!CreateProcessW(program.UTF16String, - argumentsCopy, NULL, NULL, TRUE, - CREATE_UNICODE_ENVIRONMENT, + if ([OFSystemInfo isWindowsNT]) { + size_t length; + of_char16_t *argumentsCopy; + STARTUPINFOW si; + + 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; + + length = argumentsString.UTF16StringLength; + argumentsCopy = [self + allocMemoryWithSize: sizeof(of_char16_t) + count: length + 1]; + memcpy(argumentsCopy, argumentsString.UTF16String, + (length + 1) * 2); + @try { + if (!CreateProcessW(program.UTF16String, + argumentsCopy, NULL, NULL, TRUE, + CREATE_UNICODE_ENVIRONMENT, + [self of_wideEnvironmentForDictionary: + environment], NULL, &si, &pi)) + @throw [OFInitializationFailedException + exceptionWithClass: self.class]; + } @finally { + [self freeMemory: argumentsCopy]; + } + } else { + of_string_encoding_t encoding = [OFLocale encoding]; + STARTUPINFO si; + + 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; + + if (!CreateProcessA([program cStringWithEncoding: + encoding], (char *)[argumentsString + cStringWithEncoding: encoding], NULL, NULL, TRUE, 0, [self of_environmentForDictionary: environment], NULL, &si, &pi)) @throw [OFInitializationFailedException exceptionWithClass: self.class]; - } @finally { - [self freeMemory: argumentsCopy]; } objc_autoreleasePoolPop(pool); _process = pi.hProcess; @@ -225,11 +252,11 @@ [self close]; [super dealloc]; } -- (of_char16_t *)of_environmentForDictionary: (OFDictionary *)environment +- (of_char16_t *)of_wideEnvironmentForDictionary: (OFDictionary *)environment { OFMutableData *env; OFEnumerator *keyEnumerator, *objectEnumerator; OFString *key, *object; const of_char16_t equal = '='; @@ -253,10 +280,41 @@ [env addItems: &zero count: 1]; } [env addItems: zero count: 2]; + + return env.mutableItems; +} + +- (char *)of_environmentForDictionary: (OFDictionary *)environment +{ + of_string_encoding_t encoding = [OFLocale encoding]; + OFMutableData *env; + OFEnumerator *keyEnumerator, *objectEnumerator; + OFString *key, *object; + + if (environment == nil) + return NULL; + + env = [OFMutableData data]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + while ((key = [keyEnumerator nextObject]) != nil && + (object = [objectEnumerator nextObject]) != nil) { + [env addItems: [key cStringWithEncoding: encoding] + count: [key cStringLengthWithEncoding: encoding]]; + [env addItems: "=" + count: 1]; + [env addItems: [object cStringWithEncoding: encoding] + count: [object cStringLengthWithEncoding: encoding]]; + [env addItems: "" + count: 1]; + } + [env addItems: "\0" + count: 2]; return env.mutableItems; } - (bool)lowlevelIsAtEndOfStream