Index: src/OFProcess.h ================================================================== --- src/OFProcess.h +++ src/OFProcess.h @@ -27,10 +27,14 @@ #ifdef _WIN32 # include #endif +@class OFString; +@class OFArray; +@class OFDictionary; + /*! * @brief A class for stream-like communication with a newly created process. */ @interface OFProcess: OFStream { @@ -79,10 +83,31 @@ */ + (instancetype)processWithProgram: (OFString*)program programName: (OFString*)programName arguments: (OFArray*)arguments; +/*! + * @brief Creates a new OFProcess with the specified program, program name, + * arguments and environment and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or nil + * @param environment The environment to pass to the program, or nil. If it is + * non-nil, the passed dictionary will be used to override + * the environment. If you want to add to the existing + * environment, you need to get the existing environment + * first, copy it, modify it and then pass it. + * @return A new, autoreleased OFProcess. + */ ++ (instancetype)processWithProgram: (OFString*)program + programName: (OFString*)programName + arguments: (OFArray*)arguments + environment: (OFDictionary*)environment; + /*! * @brief Initializes an already allocated OFProcess with the specified program * and invokes the program. * * @param program The program to execute. If it does not start with a slash, the @@ -116,14 +141,37 @@ */ - initWithProgram: (OFString*)program programName: (OFString*)programName arguments: (OFArray*)arguments; +/*! + * @brief Initializes an already allocated OFProcess with the specified program, + * program name, arguments and environment and invokes the program. + * + * @param program The program to execute. If it does not start with a slash, the + * search path specified in PATH is used. + * @param programName The program name for the program to invoke (argv[0]). + * Usually, this is equal to program. + * @param arguments The arguments to pass to the program, or nil + * @param environment The environment to pass to the program, or nil. If it is + * non-nil, the passed dictionary will be used to override + * the environment. If you want to add to the existing + * environment, you need to get the existing environment + * first, copy it, modify it and then pass it. + * @return An initialized OFProcess. + */ +- initWithProgram: (OFString*)program + programName: (OFString*)programName + arguments: (OFArray*)arguments + environment: (OFDictionary*)environment; + +- (void)OF_setEnvironment: (OFDictionary*)dictionary; + /*! * @brief Closes the write direction of the process. * * This method needs to be called for some programs before data can be read, * since some programs don't start processing before the write direction is * closed. */ - (void)closeForWriting; @end Index: src/OFProcess.m ================================================================== --- src/OFProcess.m +++ src/OFProcess.m @@ -15,19 +15,25 @@ */ #include "config.h" #include +#include #ifndef _WIN32 # include # include #endif + +#ifdef __MACH__ +# include +#endif #import "OFProcess.h" #import "OFString.h" #import "OFArray.h" +#import "OFDictionary.h" #import "OFInitializationFailedException.h" #import "OFReadFailedException.h" #import "OFWriteFailedException.h" @@ -34,10 +40,14 @@ #ifdef _WIN32 # include #endif #import "autorelease.h" + +#ifndef __MACH__ +extern char **environ; +#endif @implementation OFProcess + (instancetype)processWithProgram: (OFString*)program { return [[[self alloc] initWithProgram: program] autorelease]; @@ -56,29 +66,53 @@ { return [[[self alloc] initWithProgram: program programName: programName arguments: arguments] autorelease]; } + ++ (instancetype)processWithProgram: (OFString*)program + programName: (OFString*)programName + arguments: (OFArray*)arguments + environment: (OFDictionary*)environment +{ + return [[[self alloc] initWithProgram: program + programName: programName + arguments: arguments + environment: environment] autorelease]; +} + +- initWithProgram: (OFString*)program +{ + return [self initWithProgram: program + programName: program + arguments: nil + environment: nil]; +} - initWithProgram: (OFString*)program + arguments: (OFArray*)arguments { return [self initWithProgram: program programName: program - arguments: nil]; + arguments: arguments + environment: nil]; } - initWithProgram: (OFString*)program + programName: (OFString*)programName arguments: (OFArray*)arguments { return [self initWithProgram: program programName: program - arguments: arguments]; + arguments: arguments + environment: nil]; } - initWithProgram: (OFString*)program programName: (OFString*)programName arguments: (OFArray*)arguments + environment: (OFDictionary*)environment { self = [super init]; @try { #ifndef _WIN32 @@ -103,10 +137,13 @@ cStringUsingEncoding: OF_STRING_ENCODING_NATIVE]; argv[i + 1] = NULL; + if (environment != nil) + [self OF_setEnvironment: environment]; + close(readPipe[0]); close(writePipe[1]); dup2(writePipe[0], 0); dup2(readPipe[1], 1); execvp([program cStringUsingEncoding: @@ -222,10 +259,55 @@ @throw e; } return self; } + +- (void)OF_setEnvironment: (OFDictionary*)environment +{ + OFEnumerator *keyEnumerator, *objectEnumerator; + char **envp; + size_t i, count; + + count = [environment count]; + envp = [self allocMemoryWithSize: sizeof(char*) + count: count + 1]; + + keyEnumerator = [environment keyEnumerator]; + objectEnumerator = [environment objectEnumerator]; + + for (i = 0; i < count; i++) { + OFString *key; + OFString *object; + size_t keyLen, objectLen; + + key = [keyEnumerator nextObject]; + object = [objectEnumerator nextObject]; + + keyLen = [key lengthOfBytesUsingEncoding: + OF_STRING_ENCODING_NATIVE]; + objectLen = [object lengthOfBytesUsingEncoding: + OF_STRING_ENCODING_NATIVE]; + + envp[i] = [self allocMemoryWithSize: keyLen + objectLen + 2]; + + memcpy(envp[i], [key cStringUsingEncoding: + OF_STRING_ENCODING_NATIVE], keyLen); + envp[i][keyLen] = '='; + memcpy(envp[i] + keyLen + 1, [object cStringUsingEncoding: + OF_STRING_ENCODING_NATIVE], objectLen); + envp[i][keyLen + objectLen + 1] = '\0'; + } + + envp[i] = NULL; + +#ifdef __MACH__ + *_NSGetEnviron() = envp; +#else + environ = envp; +#endif +} - (BOOL)lowlevelIsAtEndOfStream { #ifndef _WIN32 if (readPipe[0] == -1)