Cocoa wrapper for an interactive Unix command
Asked Answered
E

2

9

Ok, so I know you can make an NSTask to run command line tools with Objective-C:

NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/gdb"];
[task launch];

I'm just wondering if there's a way to communicate with interactive command line tools such a as gdb. This would involve giving the command inputs based on user interaction (like run, kill or quit with gdb) and then reacting based on the information it outputs.

Egocentric answered 15/6, 2012 at 5:23 Comment(0)
T
3

You can use NSTask's setStandardInput:, setStandardOutput: and setStandardError: selectors in conjunction with NSPipe instances to communicate with the launched program.

For example, to read the task's output:

task = [[NSTask alloc] init];
[task setStandardOutput: [NSPipe pipe]];
[task setStandardError: [task standardOutput]]; // Get standard error output too
[task setLaunchPath: @"/usr/bin/gdb"];
[task launch];

You can then obtain an NSFileHandle instance that you can use to read the task's output with:

NSFileHandle *readFromMe = [[task standardOutput] fileHandleForReading]; 

To set up a pipe for sending commands to gdb, you would add

[task setStandardInput: [NSPipe pipe]];

before you launch the task. Then you get the NSFileHandle with

NSFileHandle *writeToMe = [[task standardInput] fileHandleForWriting];
Taxeme answered 15/6, 2012 at 5:55 Comment(2)
Cheers! Would you use something like NSData *data = [inString dataUsingEncoding:NSUTF8StringEncoding]; [writeToMe writeData:data]; to send commends? I've tried it but it doesn't seem to work.Egocentric
@bjz That should work. Don't forget to append a \n to the end of the string to simulate the user hitting return after typing a command.Taxeme
O
3

Use setStandardInput: and setStandardOutput: methods of NSTaks class.

NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/usr/bin/gdb"];

NSPipe *outputpipe=[[NSPipe alloc]init];
NSPipe *errorpipe=[[NSPipe alloc]init];
NSFileHandle *output,*error;

[task setArguments: arguments];
[task setStandardOutput:outputpipe];
[task setStandardError:errorpipe];

NSLog(@"%@",arguments);

output=[outputpipe fileHandleForReading];    
error=[errorpipe  fileHandleForReading];    
[task launch]; 

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedData:)  name: NSFileHandleReadCompletionNotification object:output];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedError:)  name: NSFileHandleReadCompletionNotification object:error];    
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(TaskCompletion:)  name: NSTaskDidTerminateNotification object:task];

//[input writeData:[NSMutableData initWithString:@"test"]];
[output readInBackgroundAndNotify];
[error readInBackgroundAndNotify];

[task waitUntilExit];
[outputpipe release];
[errorpipe release];
[task release];

-(void) receivedData:(NSNotification*) rec_not {
    NSFileHandle *out=[[task standardOutput] fileHandleForReading]; 
    NSData *dataOutput=[[rec_not userInfo] objectForKey:NSFileHandleNotificationDataItem];

    if( !dataOutput)
        NSLog(@">>>>>>>>>>>>>>Empty Data");

    NSString *strfromdata=[[NSString alloc] initWithData:dataOutput encoding:NSUTF8StringEncoding];    
    [out readInBackgroundAndNotify];
    [strfromdata release];
}

/* Called when there is some data in the error pipe */
-(void) receivedError:(NSNotification*) rec_not {
    NSFileHandle *err=[[task standardError] fileHandleForReading];  
    NSData *dataOutput=[[rec_not userInfo] objectForKey:NSFileHandleNotificationDataItem];

    if( !dataOutput)    
        NSLog(@">>>>>>>>>>>>>>Empty Data");
    else {
        NSString *strfromdata=[[NSString alloc] initWithData:dataOutput encoding:NSUTF8StringEncoding];
    [strfromdata release];
    }
    [err readInBackgroundAndNotify];
}

/* Called when the task is complete */
-(void) TaskCompletion :(NSNotification*) rec_not { 
    NSLog(@"task ended");
}
Ovule answered 15/6, 2012 at 6:2 Comment(1)
Hi, have you gotten this to work? I seem to have to problems implementing this. I do not get any of the notifications. I am using this to perform a git clone. I need the notifications to let me know when it is asking me for the username and the password. Any help?Colubrid

© 2022 - 2024 — McMap. All rights reserved.