Good morning to all,
May I ask your input in understanding a couple of issues ( I am sure there are probably more) relating to NSTask.
Some background. I am working on writing/understanding a Hash class, so in the process wrote a Foundation command line app that tries to illustrate to me how it works.
So, there are three stages in the code. ( I have included the entire code in case someone actually wishes to run it).
First stage...simply runs an MD5 command line app using NSTask. The arguments are supplied with NSTask's setArguments, and the stdOutput is used to display the result.
Next...I use a pipe to read the result from the StdOutput
Finally, I try and pipe "in" the arguments and read the output.
There are 2 issues that I would like to understand.
1) Even though I have added the "Terminal" class as an observer, it does not trigger the notification as I would have expected. What am I missing?
2) The output from the 3rd version is different from the first 2. ( In the first 2 iterations, I supply the switch "-s" and the string to be hashed as arguments in setArguments. In the Final iteration, I supply the switch and argument as a single string. I suspect I might not fully understand the intricacies of setArgument vs "piping" in the switch and argument as one. I had tried supplying the argument "-s" with setArgument and the string solely in the pipe, but this would not work. Only an "inpipe" with both got any sort of result.
Thanks for our input.
Here is the full code. It's a foundation tool app. I apologize for all the code but feel that it's all pretty relevant. Hope no-one is offended, and will gladly take advice on this for future reference. Just , that I have hit a wall for most of the week and feel it's too big a knowledge gap to just move on to the next issue before at least understanding this.
Thanks as always in advance.
Please be kind
Program name: HashClassImplementation
HashClassImplementation.m
Terminal.h
Terminal.m
May I ask your input in understanding a couple of issues ( I am sure there are probably more) relating to NSTask.
Some background. I am working on writing/understanding a Hash class, so in the process wrote a Foundation command line app that tries to illustrate to me how it works.
So, there are three stages in the code. ( I have included the entire code in case someone actually wishes to run it).
First stage...simply runs an MD5 command line app using NSTask. The arguments are supplied with NSTask's setArguments, and the stdOutput is used to display the result.
Next...I use a pipe to read the result from the StdOutput
Finally, I try and pipe "in" the arguments and read the output.
There are 2 issues that I would like to understand.
1) Even though I have added the "Terminal" class as an observer, it does not trigger the notification as I would have expected. What am I missing?
2) The output from the 3rd version is different from the first 2. ( In the first 2 iterations, I supply the switch "-s" and the string to be hashed as arguments in setArguments. In the Final iteration, I supply the switch and argument as a single string. I suspect I might not fully understand the intricacies of setArgument vs "piping" in the switch and argument as one. I had tried supplying the argument "-s" with setArgument and the string solely in the pipe, but this would not work. Only an "inpipe" with both got any sort of result.
Thanks for our input.
Here is the full code. It's a foundation tool app. I apologize for all the code but feel that it's all pretty relevant. Hope no-one is offended, and will gladly take advice on this for future reference. Just , that I have hit a wall for most of the week and feel it's too big a knowledge gap to just move on to the next issue before at least understanding this.
Thanks as always in advance.
Please be kind
Program name: HashClassImplementation
HashClassImplementation.m
Code:
#import <Foundation/Foundation.h>
//#import <Cocoa/Cocoa.h>
//#import "HashValue.h"
#import "Terminal.h"
#define MD5PATH @"/sbin/md5"
#define SHA256PATH @"/usr/bin/shasum"
#define HMAC256PATH @"/Developer/SDKs/MacOSX10.6.sdk/usr/include/CommonCrypto/CommonHMAC/CCHmac"
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSFileHandle *fileHandleForReading = nil;
NSFileHandle *fileHandleForWriting = nil;
/*Enter test string here*/
NSString *testString = @"Some data value.";
NSLog(@"Test against a standard using terminal");
NSLog(@"Test of MD5 hash algorithm");
NSLog(@"Test string is: \"%@\"", testString);
NSLog(@"\n\nFirst test will simply write the hash to the terminal");
Terminal *terminal = [[ Terminal alloc]initWithPath:MD5PATH];
[terminal setArgsOfTask: @"-s" arg2:testString arg3:nil];
[terminal launch];
NSLog(@"Task's Current directory: %@", [terminal currenWorkingirectory] );
[terminal terminate];
[terminal terminateObserverStatus];
NSLog(@"-->\n\nNext test will pipe result to be read by a string and displayed");
terminal = [[ Terminal alloc]initWithPath:MD5PATH];
[terminal setArgsOfTask: @"-s" arg2:testString arg3:nil];
[terminal setPipeOut];
fileHandleForReading = [terminal outFileHandle];
[terminal launch];
NSData *outData = [fileHandleForReading readDataToEndOfFile];
NSLog(@"Data collected through pipe: %@", outData);
NSString * readData = [[NSString alloc]initWithData:outData encoding:NSUTF8StringEncoding];
NSLog(@"Result as string: %@", readData);
[readData release];
[terminal terminate];
[fileHandleForReading release];
[terminal terminateObserverStatus];
NSLog(@"-->\n\nNext test will pipe in the string and the result to be read by a string and displayed");
terminal = [[ Terminal alloc]initWithPath:MD5PATH];
//[terminal setArgsOfTask: @"-s" arg2:nil arg3:nil];
[terminal setPipeOut];
[terminal setPipeIn];
fileHandleForReading = [terminal outFileHandle];
fileHandleForWriting = [terminal inFileHandle];
NSString * fullCommandLine = [@"-s" stringByAppendingString:testString];
NSData * stringAsData = [fullCommandLine dataUsingEncoding:NSUTF8StringEncoding];
[fileHandleForWriting writeData:stringAsData];
[fileHandleForWriting closeFile];
[terminal launch];
NSData *outData2 = [fileHandleForReading readDataToEndOfFile];
NSString * readData2 = [[NSString alloc]initWithData:outData2 encoding:NSUTF8StringEncoding];
NSLog(@"Result as string:\n%@", readData2);
[terminal terminate];
[fileHandleForReading release];
[terminal terminateObserverStatus];
[pool drain];
return 0;
}
Terminal.h
Code:
#import <Foundation/Foundation.h>
@interface Terminal : NSObject {
NSString * string;
NSString * digest;
NSTask *_task;
NSFileHandle *_inHandle;
NSFileHandle *_outHandle;
}
@property(readwrite, retain) NSString *string;
@property(readwrite, retain) NSString *digest;
@property(readwrite, retain) NSTask *task;
@property(readwrite, retain) NSFileHandle * inFileHandle;
@property(readwrite, retain)NSFileHandle * outFileHandle;
-(id) initWithPath: (NSString *) aPath;
-(void) setArgsOfTask:(NSString *)arg1
arg2:(NSString*) arg2
arg3:(NSString *) arg3;
-(void) setPipeOut;
-(void) setPipeIn;
-(NSFileHandle *) outFileHandle;
-(NSFileHandle *) inFileHandle;
-(void) launch;
-(void) terminate;
-(void) terminateObserverStatus;
-(NSString *) currenWorkingirectory;
-(void)waitUntilExit;
@end
Terminal.m
Code:
#import "Terminal.h"
typedef enum
{
ATASK_SUCCESS_VALUE = 0
}
SUCCESS_STATUS;
@implementation Terminal
@synthesize string, digest, task = _task, outFileHandle = _outFileHandle, inFileHandle = _inFileHandle;
#pragma mark initializers
-(void) dealloc
{
[super dealloc];
}
-(id) initWithPath: (NSString *) aPath
{
self = [super init];
if (self)
{
[self setTask:[[NSTask alloc] init]];
[[self task] setLaunchPath:aPath];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(checkATaskStatus:)
name:NSTaskDidTerminateNotification
object:nil];
/* make @class terminal a delegate of Application? */
}
return self;
}
-(void) terminateObserverStatus
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark task methods
-(void) setArgsOfTask:(NSString *)arg1
arg2:(NSString*) arg2
arg3:(NSString *) arg3
{
NSArray * arr = nil;
if (arg2 == nil && arg3 == nil) {
arr = [NSArray arrayWithObject:arg1];
}
else if ( arg3 == nil)
{
arr = [NSArray arrayWithObjects:arg1, arg2, nil];
}
else {
arr = [NSArray arrayWithObjects:arg1, arg2, arg3, nil];
}
[[self task] setArguments:arr];
}
#pragma mark setThePipes
-(void) setPipeOut
{
NSPipe *pipeOut = [NSPipe pipe];
[[self task] setStandardOutput:pipeOut];
}
-(void) setPipeIn
{
NSPipe *pipeIn = [NSPipe pipe];
[[self task] setStandardInput:pipeIn];
}
-(NSFileHandle *) outFileHandle
{
NSPipe * stdOut = [[self task] standardOutput];
return [stdOut fileHandleForReading];
}
-(NSFileHandle *) inFileHandle
{
NSPipe *stdIn = [[ self task] standardInput];
return [stdIn fileHandleForWriting];
}
#pragma mark launch methods
-(void) launch
{
[[self task] launch];
}
- (void)checkATaskStatus:(NSNotification *)aNotification {
NSLog(@"Notification: %@",[ aNotification name]);
int status = [[aNotification object] terminationStatus];
if (status == ATASK_SUCCESS_VALUE)
NSLog(@"Task succeeded.");
else
NSLog(@"Task failed.");
}
-(void) terminate
{
[[self task ]terminate];
[self setTask:nil];
}
-(NSString *) currenWorkingirectory
{
return [ [self task ] currentDirectoryPath];
}
-(void)waitUntilExit
{
[[self task] waitUntilExit];
}
#pragma mark setFileHandles
@end