News Software Download Buy Now About Us Developers Contact
software TOC | PREV | NEXT
/* SDLogTask.h created by andrew on Thu 30-Apr-1998 */
//
// A wrapper of some intense multi-threaded code
// To allow you to spawn a task and see the errors
//

#import <AppKit/AppKit.h>

@interface SDLogTask : NSObject
{
    id owner;
    NSTextView *logText;
    NSTask *task;
    BOOL includeStandardOutput;
    NSPipe *standardErrorPipe;
    NSPipe *standardOutputPipe;
    NSFileHandle *standardErrorHandle;
    NSFileHandle *standardOutputHandle;
}

//
// executable is full path to program
// args is an array of strings of the arguments
// send in an NSTextView if you want console behaviour
// includeStandardOut: is YES if you also want stdout logged to Text
//

- initAndLaunchWithArgs:(NSArray *)args executable:(NSString *)pathToExe directory:(NSString *)dir logToText:(NSTextView *)text includeStandardOutput:(BOOL)includeStandardOut owner:anOwner;

@end

//
// SDLogTask.m
//

/* SDLogTask.m created by andrew on Thu 30-Apr-1998 */

#import "SDLogTask.h"

// kudos to bbum@codefab.com for helping me fix IO:
#import "
NSFileHandle_CFRNonBlockingIO.h"

//
// If you want notification when the task completes
// implement this method in the "owner" class
//

@interface NSObject(SDLogTask_Delegate)
- (void)taskTerminated:(BOOL)success;
@end

@implementation SDLogTask

//
// Methods to make it easy to spew feedback to user:
//

#define END_RANGE NSMakeRange([[logText string]length],0)

- (void)appendString:(NSString *)string newLine:(BOOL)newLine
{
    [logText replaceCharactersInRange:END_RANGE withString:string];
    if (newLine)
        [logText replaceCharactersInRange:END_RANGE withString:@"\n"];
    else
        [logText replaceCharactersInRange:END_RANGE withString:@" "];

    if ([[logText window] isVisible]) {
        [logText scrollRangeToVisible:END_RANGE];
    }
}

- (void)outputData:(NSData *)data
{
    [self appendString:[[[NSString alloc]initWithData:data encoding:[NSString defaultCStringEncoding]]autorelease] newLine:YES];
}


- (void) processAvailableData;
{
    NSData *data;
    BOOL dataProcessed;

    dataProcessed = NO;
    data = [standardErrorHandle availableDataNonBlocking];
    if ( (data != nil) && ([data length] != 0) ) {
        [self outputData:data];
        dataProcessed = YES;
    }

if (includeStandardOutput) {
        data = [standardOutputHandle availableDataNonBlocking];
        if ( (data != nil) && ([data length] != 0) ) {
            [self outputData:data];
            dataProcessed = YES;
        }
    }

    if ([task isRunning] == YES) {
        if (dataProcessed == YES)
            [self performSelector: @selector(processAvailableData)
                withObject: nil afterDelay: .1];
else
        [self performSelector: @selector(processAvailableData)
                withObject: nil afterDelay: 2.5];
    }
}


- (void) outputInfoAtStart:(NSString *)pathToExe args:(NSArray *)args
{
    int i;
    // clear it out from last time:
    [logText setString:@""];

    [self appendString:pathToExe newLine:NO];
    for (i = 0; i < [args count]; i++)
        [self appendString:[args objectAtIndex:i] newLine:NO];
    [self appendString:@"\n" newLine:YES];
}

- initAndLaunchWithArgs:(NSArray *)args executable:(NSString *)pathToExe directory:(NSString *)dir logToText:(NSTextView *)text includeStandardOutput:(BOOL)includeStandardOut owner:anOwner
{
    [super init];
    logText = text;
includeStandardOutput = includeStandardOut;
    owner = anOwner;

    standardErrorPipe = [NSPipe pipe];
    standardErrorHandle = [standardErrorPipe fileHandleForReading];

    if (includeStandardOutput) {
standardOutputPipe = [NSPipe pipe];
standardOutputHandle = [standardOutputPipe fileHandleForReading];
    }

    task = [[NSTask alloc] init];

[task setArguments:args];
    [task setCurrentDirectoryPath:dir];
[task setLaunchPath:pathToExe];

    [task setStandardError:standardErrorPipe];
    if (includeStandardOutput) [task setStandardOutput:standardOutputPipe];

[self outputInfoAtStart:pathToExe args:args];


    [self performSelector: @selector(processAvailableData) withObject: nil afterDelay: 1.0];
    
    // HERE WE GO: spin off a thread to do this:
    [task launch];

    [[NSNotificationCenter defaultCenter]
        addObserver: self
        selector: @selector(checkATaskStatus:)
        name: NSTaskDidTerminateNotification
        object: task];
    return self;
}

#define TASK_SUCCEEDED NSLocalizedStringFromTable(@"\nJob SUCCEEDED!\n", @"GIFfun", "message when task is successful")

#define TASK_FAILED NSLocalizedStringFromTable(@"\nJob FAILED!\n\nPlease see log.", @"GIFfun", "when the task fails...")


- (void)checkATaskStatus:(NSNotification *)aNotification
{
    int status = [[aNotification object] terminationStatus];
    if (status == 0 /* STANDARD SILLY UNIX RETURN VALUE */) {
        [self appendString:TASK_SUCCEEDED newLine:YES];
    } else {
        [self appendString:TASK_FAILED newLine:YES];
        [[logText window] orderFront:self];
    }
    if ([owner respondsToSelector:@selector(taskTerminated:)])
        [owner taskTerminated:(status == 0)];
}

@end
TOC | PREV | NEXT
Created by Stone Design's Create on 4/30/1998
©2000 Stone Design top