at_yasu's blog

ロード的なことを

NSTask と std{out,err}

Cocoa アプリケーションで別プログラム(コマンドライン)を動かす時、stdout,stderrの出力を受け取る方法。


Cocoa で別のコマンドラインプログラムを動かそうとすると、NSTask を利用する事になる。このNSTask は BSD (*NIX)で言うfork関数をCocoaに合わした形のクラスになっている。


具体的に言うと、

-(void) setLaunchPath :(NSString *)path
-(void) setArguments :(NSArray *)argument
-(void) setStandardOutput:(NSPipe*)pipe
-(void) setStandardError:(NSPipe*)pipe
-(void) launch
-(BOOL) isRunning
-(int) terminationStatus
-(void) waitUntilExit

といった関数がある。

setLaunchPath
実行するプログラムまでのパスを設定する。
setArguments
プログラムを実行する時に、プログラムに渡す引数。NSArrayの配列の全ての要素はNSString型でなければならない。
setStandardOutput
引数のNSPipeが、プログラムが『標準出力』で書き出した内容を保持する。
setStandardError
引数のNSPipeが、プログラムの『エラー出力』で書き出した内容を保持する。
launch
プログラムを実行する。
isRunning
プログラムが実行しているか確認する関数。YESの場合実行しており、NOの場合は実行していない。
terminationStatus
プログラムが終了した際のステータス番号。sys/errno.h を参照。
waitUntilExit
プログラムが終了するまで待機する関数。

以下、簡単な実行例。

@interface MyWindow : NSWindow
{
    IBOutlet NSTextField *argument;
    IBOutlet NSTextField *stderrField;
    IBOutlet NSTextField *stdoutField;
}
- (IBAction)exec:(id)sender;
@end

@implementation MyWindow

- (IBAction)exec:(id)sender
{
    NSTask *task = [[NSTask alloc] init];
    NSPipe *stdoutPipe = [[NSPipe alloc] init];
    NSPipe *stderrPipe = [[NSPipe alloc] init];
    NSArray *arr = [NSArray arrayWithObjects:[argument stringValue]];
    
    [task setLaunchPath:@"/bin/echo"];
    [task setArguments:arr];
    [task setStandardOutput:stdoutPipe];
    [task setStandardError:stderrPipe];
    
    // Launch the process.
    [task launch];
    [task waitUntilExit];
    
    // End launch process.
    // Output data setting.
    NSData *outData = [[stdoutPipe fileHandleForReading] availableData];
    NSData *errData = [[stderrPipe fileHandleForReading] availableData];
    
    const char *outChar = (const char*)[outData bytes];
    const char *errChar = (const char*)[errData bytes];
    NSString *outStr = nil;
    NSString *errStr = nil;

    outStr = (outChar) ? [NSString stringWithCString:outChar
                                          encoding:NSASCIIStringEncoding]
                       : [NSString string];

    errStr = (errChar) ? [NSString stringWithCString:errChar
                                            encoding:NSASCIIStringEncoding]
                       : [NSString string];

    [stdoutField setStringValue:outStr];
    [stderrField setStringValue:errStr];

    [task release];
    [stdoutPipe release];
    [stderrPipe release];
}

@end


ところで、Safariとか動かすにはどうするか見事に忘れた・・・orz