Re: Wrapping an Interactive Unix Executable (update)
Re: Wrapping an Interactive Unix Executable (update)
- Subject: Re: Wrapping an Interactive Unix Executable (update)
- From: email@hidden
- Date: Fri, 17 Dec 2004 13:14:35 -0600
Hi,
I'm afraid I only have very limited knowledge of the debugger, but as I was
about to try and use it I realized that my program was actually running stably
(i.e. it wasn't crashing like I thought it was), but I wasn't getting any
output at all.
Anyway, I thought your suggestion to try and wrap a simpler executable was an
excellent idea, so I was going to wrap the Evaluator executable used in the
MathPaper project, which I know works. However, I decided to first try and use
the existing wrapper for Evaluator and simply drop in my executable. And, of
course, it worked just fine. So I did some investigation, and I realized that
the code is set up as a document based application, whereas my program is not.
Consequently there is no controller class per se, but the window delegates to
the File's Owner. This is why the launching of the executable is handled in an
overriden windowDidLoad. In my program I wound up trying to accomplish the same
task in awakenFromNib, since the controller does not respond to windowDidLoad.
Also, the program was getting its input in the textDidChange delegate method,
whereas I was using an IBAction. I figured I could get away with this because
the program uses one big TextView, essentially emulating a terminal, whereas I
was using a searchfield for the input and a textview for the output. I think
the problem may lie here, as there is probably notificationcenter stuff going
on here that I know nothing about.
So, I guess my task now is figuring out how to convert this code for use in a
non-document-based application. Following is the code for three applications,
my working but inefficient version, the non-working updated version, and the
MathPaper wrapper with my executable dropped in:
First, the current, working version of my application:
/* Controller */
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject
{
IBOutlet id searchField;
IBOutlet id textView;
IBOutlet id translator;
IBOutlet id window;
}
- (IBAction)translate:(id)sender;
@end
#import "Controller.h"
#import "Translator.h"
@implementation Controller
- (void)awakeFromNib
{
[window center];
}
- (IBAction)translate:(id)sender
{
[[textView textStorage] setAttributedString:[translator
translateWord:[searchField stringValue]]];
[[textView textStorage] setFont:[NSFont userFixedPitchFontOfSize:0]];
[searchField selectText:self];
}
@end
/* Translator */
#import <Cocoa/Cocoa.h>
@interface Translator : NSObject
{
}
- (NSAttributedString *)translateWord:(NSString *)word;
@end
#import "Translator.h"
@implementation Translator
- (NSAttributedString *)translateWord:(NSString *)word
{
NSTask * translator;
NSPipe * standardOutput;
NSString * path;
standardOutput = [NSPipe pipe];
path = [[NSBundle mainBundle] pathForResource:@"words" ofType:@""];
translator = [[NSTask alloc] init];
[translator setCurrentDirectoryPath:[path stringByDeletingLastPathComponent]];
[translator setLaunchPath:path];
[translator setArguments:[NSArray arrayWithObject:word]];
[translator setStandardOutput:standardOutput];
[translator launch];
[translator waitUntilExit];
NSAttributedString * output = [[[NSAttributedString alloc]
initWithString:[[[NSString alloc] initWithData:[[standardOutput
fileHandleForReading] availableData] encoding:NSISOLatin1StringEncoding]
autorelease]] autorelease];
[translator terminate];
[translator release];
return output;
}
@end
Now here's the code for the attempted update:
/* Controller */
#import <Cocoa/Cocoa.h>
@interface Controller : NSWindowController
{
IBOutlet id searchField;
IBOutlet id textView;
IBOutlet id window;
NSTask * translator;
NSPipe * toPipe;
NSPipe * fromPipe;
NSFileHandle * toTranslator;
NSFileHandle * fromTranslator;
}
- (IBAction)translate:(id)sender;
@end
#import "Controller.h"
@implementation Controller
- (void)awakeFromNib
{
NSString * path;
[window center];
path = [[NSBundle mainBundle] pathForResource:@"words" ofType:@""];
toPipe = [NSPipe pipe];
fromPipe = [NSPipe pipe];
toTranslator = [toPipe fileHandleForWriting];
fromTranslator = [fromPipe fileHandleForReading];
translator = [[NSTask alloc] init];
[translator setCurrentDirectoryPath:[path stringByDeletingLastPathComponent]];
[translator setLaunchPath:path];
[translator setStandardInput:toPipe];
[translator setStandardOutput:fromPipe];
[translator launch];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(gotData:) name:NSFileHandleReadCompletionNotification
object:fromTranslator];
[fromTranslator readInBackgroundAndNotify];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[translator terminate];
[translator release];
[super dealloc];
}
- (void)gotData:(NSNotification *)notification
{
NSData * data;
NSString * string;
NSAttributedString * output;
data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
output = [[NSAttributedString alloc] initWithString:string];
[[textView textStorage] setAttributedString:output];
[fromTranslator readInBackgroundAndNotify];
// [string release];
// [output release];
}
- (IBAction)translate:(id)sender
{
[toTranslator writeData:[[searchField stringValue]
dataUsingEncoding:NSASCIIStringEncoding]];
[searchField selectText:nil];
return;
}
@end
Finally here is the code that works from the book, but with the document-based
nature:
// MathDocument.h
#import <Cocoa/Cocoa.h>
@interface MathDocument : NSDocument
{
}
@end
// MathDocument.m
#import "MathDocument.h"
#import "PaperController.h"
@implementation MathDocument
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document
supports multiple NSWindowControllers, you should remove this method and
override -makeWindowControllers instead.
return @"PaperWindow";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that need to be executed once the windowController has
loaded the document's window.
}
- (NSData *)dataRepresentationOfType:(NSString *)aType
{
// Insert code here to write your document from the given data. You can
also choose to override -fileWrapperRepresentationOfType: or
-writeToFile:ofType: instead.
return nil;
}
- (BOOL)loadDataRepresentation:(NSData *)data ofType:(NSString *)aType
{
// Insert code here to read your document from the given data. You can also
choose to override -loadFileWrapperRepresentation:ofType: or
-readFromFile:ofType: instead.
return YES;
}
// Override the NSDocument makeWindowControllers
// method to specify our own controller.
- (void)makeWindowControllers
{
id ctl = [ [PaperController alloc]
initWithWindowNibName:[self windowNibName] ];
[ctl autorelease]; // addWindowController will retain...
[self addWindowController:ctl];
}
@end
#import "PaperController.h"
@implementation PaperController
- (void)windowDidLoad
{
NSString *path=0;
[super windowDidLoad];
[ [self window] makeFirstResponder:theText];
path = [ [NSBundle mainBundle]
pathForResource:@"words" ofType:@""];
toPipe = [NSPipe pipe];
fromPipe = [NSPipe pipe];
toEvaluator = [toPipe fileHandleForWriting];
fromEvaluator = [fromPipe fileHandleForReading];
evaluator = [ [NSTask alloc] init];
[evaluator setCurrentDirectoryPath:[path stringByDeletingLastPathComponent]];
[evaluator setLaunchPath:path];
[evaluator setStandardOutput:fromPipe];
[evaluator setStandardInput:toPipe];
[evaluator launch];
[ [NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(gotData:)
name:NSFileHandleReadCompletionNotification
object:fromEvaluator];
[fromEvaluator readInBackgroundAndNotify];
}
- (void)dealloc
{
[ [NSNotificationCenter defaultCenter] removeObserver:self];
[evaluator terminate];
[evaluator release];
[super dealloc];
}
// NSTextView delegate method -textDidChange:
// If current event is a carriage return do special processing
- (void)textDidChange:(NSNotification *)notification
{
NSString *str = [ [ [self window] currentEvent] characters];
if ([str isEqualToString:@"\r"]) {
// Get the last line of text and send it to the Evaluator
NSString *str = [theText string];
int i;
for (i=[str length]-2;i>=0;i--) {
if (i==0 || [str characterAtIndex:i-1] == '\n') {
NSRange llRange = NSMakeRange(i,[str length]-i);
NSString *lastLine = [str substringWithRange:llRange];
[toEvaluator writeData:
[lastLine dataUsingEncoding:NSASCIIStringEncoding
allowLossyConversion:YES] ];
// Do not allow any more changes to the text
[theText setEditable:NO];
return;
}
}
}
}
- (void)gotData:(NSNotification *)notification
{
NSData *data;
NSString *str;
data = [ [notification userInfo]
objectForKey:NSFileHandleNotificationDataItem];
str = [ [NSString alloc] initWithData:data
encoding:NSASCIIStringEncoding] ;
// Add the data to the end of theText object.
[theText appendString:str];
// [theText appendString:@"--------------------\n"];
// Scroll to the bottom.
[theText scrollRangeToVisible:
NSMakeRange([ [theText textStorage] length], 0)];
// Register to get the notification again
[fromEvaluator readInBackgroundAndNotify];
// Allow the user to type additional math expressions.
[theText setEditable:YES];
[str release];
}
- (NSString *)windowTitleForDocumentDisplayName:
(NSString *)displayName
{
return [@"MathPaper: " stringByAppendingString:displayName];
}
@end
@implementation NSTextView(MathPaper)
- (void)appendString:(NSString *)str
{
int len = [ [self textStorage] length];
[self replaceCharactersInRange:NSMakeRange(len,0)
withString:str];
}
@end
#import <Cocoa/Cocoa.h>
@interface PaperController : NSWindowController
{
NSTask *evaluator;
NSPipe *toPipe;
NSPipe *fromPipe;
NSFileHandle *toEvaluator;
NSFileHandle *fromEvaluator;
IBOutlet NSTextView *theText;
}
@end
@interface NSTextView(MathPaper)
- (void)appendString:(NSString *)str;
@end
Sorry for the horribly long email, but everyone seemed to think this was
necessary. Thanks again to everyone for all of the continued help. I really
and truly appreciate it a great deal.
Erik
On Dec 17, 2004, at 8:08, Harilaos Skiadas wrote:
Hi,
I'd be happy to show you the code, but I don't think
there is any >need,
as my latest attempt is for all intents and purposes
exactly what you
just posted. This came about because in searching
the mailing list
We need to know exactly on which place it crashes,
then we can try to figure out why. We don't have
enough info about how your application works. I assume
you have used the debugger to see exactly where the
problem is? My guess at this point would be that you
have somehow closed the connection to the other
program after reading the input.
somebody had pointed out that the source code for a
project called
MathPaper in Building Cocoa Applications: A
Step-By-Step guide is a
wrapper for an interactive unix task. I'm beginning
to think that
maybe the problem is with the way the Unix executable
is designed,
though there should be some workaround.
>From my limited experience, there is a very good
chance that the problem might lie with the executable,
though before you resort to that, you should make sure
that your code works. Try to use it with another
executable that you are sure should work (maybe one
you write yourself, that simply repeats each line the
user types? maybe such a program already exists?) If
you are sure your code is fine, then your best bet
would be to contact the author of the tool and explain
the problem to them.
Haris
__________________________________
Do you Yahoo!?
All your favorites on one personal page Try My Yahoo!
http://my.yahoo.com
__________________________________________________
mtmail: 1 GB of feature full free email.
The best thing since sliced bread. Again.
http://macteens.net
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden