Reputation: 3031
task = [NSTask new];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:[NSArray arrayWithObject:@"/applications/jarvis/brain/server.sh"]];
[task setCurrentDirectoryPath:@"/"];
NSPipe *outputPipe = [NSPipe pipe];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput:outputPipe];
[task launch];
NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
[outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease]];
}
NSArray* substrings = [outputString componentsSeparatedByString:@"Jarvis>"];
NSString* finalCharlieOutputNSTask = [substrings lastObject];
NSSpeechSynthesizer * syn = [[NSSpeechSynthesizer alloc] init];
[syn startSpeakingString:finalCharlieOutputNSTask];
self.charlieOutput.stringValue = finalCharlieOutputNSTask;
Ok, so that's my code. It launches an SH file and reads the output. BUT, I want it to wait until "Jarvis>" appears in the string before saying and printing the result. But, it seems like with the while loop, my code freezes there. Without it it reads the normal output of launching the server.sh file, but the whole thing. Any ideas why this doesn't work?
Here is the Server.sh file:
echo Starting Jarvis Program D.
ALICE_HOME=.
SERVLET_LIB=lib/servlet.jar
ALICE_LIB=lib/aliceserver.jar
JS_LIB=lib/js.jar
# Set SQL_LIB to the location of your database driver.
SQL_LIB=lib/mysql_comp.jar
# These are for Jetty; you will want to change these if you are using a different http server.
HTTP_SERVER_LIBS=lib/org.mortbay.jetty.jar
PROGRAMD_CLASSPATH=$SERVLET_LIB:$ALICE_LIB:$JS_LIB:$SQL_LIB:$HTTP_SERVER_LIBS
java -classpath $PROGRAMD_CLASSPATH -Xms64m -Xmx128m org.alicebot.server.net.AliceServer $1
Upvotes: 1
Views: 674
Reputation: 1
For non-blocking IO code for NSTask & NSFileManager also see the source code of DOCtor:
# http://www.stone.com/DOCtor/
# http://www.stone.com/DOCtor/DOCtor.tar.gz
open -e DOCTor/NSFileHandle_CFRNonBlockingIO.h \
DOCTor/NSFileHandle_CFRNonBlockingIO.m \
DOCTor/NSFileManager-Extensions.h \
DOCTor/NSFileManager-Extensions.m
Also note that many command line programs (internally) block buffer their output to stdout if stdout is a pipe and not an interactive terminal (tty). For this reason some command line programs have special options to line-buffer their output regardless of sending output to a pipe or tty.
tcpdump -l
grep --line-buffered
...
Upvotes: 0
Reputation: 11
Maybe try flushing NSPipe along the lines of code published in the article:
"NSTasks, NSPipes, and deadlocks when reading...",
http://dev.notoptimal.net/2007/04/nstasks-nspipes-and-deadlocks-when.html
Yet another approach could test the use of NSTask & NSUnbufferedIO.
You will find some example code in the book "Cocoa Programming" by Don Yacktman.
# http://www.cocoaprogramming.net
# http://www.cocoaprogramming.net/CocoaProgramming-20021010.tgz
open -e CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.h \
CocoaProgramming-20021010/Chapter\ 24/Animal/AnimalController.m \
CocoaProgramming-20021010/Chapter\ 24/Calendar/CalendarController.m
# for yet another try with sample code using waitForDataInBackgroundAndNotify see:
# http://cocoawithlove.com/2009/05/invoking-other-processes-in-cocoa.html
open -e OpenFileKiller/NSTask+OneLineTasksWithOutput.m
# --> [standardOutputFile waitForDataInBackgroundAndNotify];
Upvotes: 1
Reputation: 29928
Elijah, edit your code to look like this:
...
[task launch];
NSMutableString *outputString = [NSMutableString string];
while ([outputString rangeOfString:@"Jarvis>"].location == NSNotFound) {
[outputString appendString:[[[NSString alloc] initWithData:[[outputPipe fileHandleForReading] readDataToEndOfFile] encoding:NSUTF8StringEncoding] autorelease];
}
if ([task isRunning]) {
[task terminate];
}
NSArray *subStrings = [outputString componentsSeparatedByString:@"Jarvis>"];
...
This code within the loop will successively read output data from your file and append it to the current output, and stop reading when @"Jarvis>" is found (it will also kill the task after a @"Jarvis>" is found, so it doesn't keep running forever).
Upvotes: 1
Reputation: 16337
You want to put the readDataToEndOfFile inside the loop. Otherwise, it reads the data once, checks for existence of your string, then loops forever if it doesn't find it in that first reading.
Upvotes: 1