Commits

Peter Hosey committed b08dc03

Initial check-in of completed, but non-working, NSTask subclass. Fails because NSTask is really an abstract class, so we're not inheriting the implementations we need.

  • Participants

Comments (0)

Files changed (8)

+syntax: glob
+build
+*.swp
+
+*.mode1
+*.mode1v3
+*.mode2
+*.mode2v3
+*.pbxuser
+*.perspective
+*.perspectivev3
+xcuserdata
+
+*~.nib
+
+.DS_Store
+//
+//  PRHTask.h
+//  Revision Switcher
+//
+//  Created by Peter Hosey on 2011-10-13.
+//  Copyright 2011 Peter Hosey. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef void (^PRHTerminationBlock)(NSTask *task);
+
+@interface PRHTask : NSTask
+
+//For directing output to /dev/null.
+- (void) nullifyStandardOutput;
+- (void) nullifyStandardError;
+
+//Don't attempt to interact with NSTask's standard{Output,Error} properties if you touch these standard-{output,error} properties.
+
+//Set either or both of these before launch to have normal or error output accumulate in the appropriate data object.
+@property(nonatomic) BOOL accumulatesStandardOutput, accumulatesStandardError;
+
+//“Whitespace” here includes line breaks (whitespaceAndNewlineCharacterSet). Applies to both output and error output. Only affects the string properties; the data properties always contain the full output unmolested. Defaults to YES.
+@property(nonatomic) BOOL trimWhitespaceFromAccumulatedOutputs;
+
+//You probably should only use these after the task exits.
+//You can expect the string properties to return nil if the output data is not valid UTF-8.
+@property(nonatomic, readonly) NSData *accumulatedStandardOutputData;
+@property(nonatomic, readonly) NSString *outputStringFromStandardOutputUTF8;
+@property(nonatomic, readonly) NSData *accumulatedStandardErrorData;
+@property(nonatomic, readonly) NSString *errorOutputStringFromStandardErrorUTF8;
+
+@property(nonatomic, readonly, retain) NSError *standardOutputReadError, *standardErrorReadError;
+
+#pragma mark -
+
+@property(copy) PRHTerminationBlock successfulTerminationBlock;
+@property(copy) PRHTerminationBlock abnormalTerminationBlock;
+
+@end
+//
+//  PRHTask.m
+//  Revision Switcher
+//
+//  Created by Peter Hosey on 2011-10-13.
+//  Copyright 2011 Peter Hosey. All rights reserved.
+//
+
+#import "PRHTask.h"
+
+@interface PRHTask ()
+@property(nonatomic, readwrite, retain) NSError *standardOutputReadError, *standardErrorReadError;
+@property(nonatomic, retain) id standardOutputObserverToken, standardErrorObserverToken, taskDidTerminateObserverToken;
+@end
+
+@implementation PRHTask
+{
+	NSMutableData *accumulatedStandardOutputData, *accumulatedStandardErrorData;
+}
+
+@synthesize trimWhitespaceFromAccumulatedOutputs;
+
+@synthesize accumulatedStandardOutputData;
+@synthesize accumulatedStandardErrorData;
+
+@synthesize standardOutputReadError, standardErrorReadError;
+
+@synthesize standardOutputObserverToken, standardErrorObserverToken, taskDidTerminateObserverToken;
+
+- (NSString *) outputStringFromStandardOutputUTF8 {
+	NSString *str = [[[NSString alloc] initWithData:[self accumulatedStandardOutputData] encoding:NSUTF8StringEncoding] autorelease];
+
+	if (self.trimWhitespaceFromAccumulatedOutputs)
+		str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+	return str;
+}
+- (NSString *) errorOutputStringFromStandardErrorUTF8 {
+	NSString *str = [[[NSString alloc] initWithData:[self accumulatedStandardErrorData] encoding:NSUTF8StringEncoding] autorelease];
+
+	if (self.trimWhitespaceFromAccumulatedOutputs)
+		str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+	return str;
+}
+
+- (BOOL) accumulatesStandardOutput {
+	return (accumulatedStandardOutputData != nil);
+}
+- (void) setAccumulatesStandardOutput:(BOOL)flag {
+	if (flag && !accumulatedStandardOutputData) {
+		accumulatedStandardOutputData = [[NSMutableData alloc] init];
+		[self setStandardOutput:[NSPipe pipe]];
+	} else if (accumulatedStandardOutputData && !flag) {
+		[accumulatedStandardOutputData release];
+		accumulatedStandardOutputData = nil;
+		[self setStandardOutput:nil];
+	}
+}
+- (BOOL) accumulatesStandardError {
+	return (accumulatedStandardErrorData != nil);
+}
+- (void) setAccumulatesStandardError:(BOOL)flag {
+	if (flag && !accumulatedStandardErrorData) {
+		accumulatedStandardErrorData = [[NSMutableData alloc] init];
+		[self setStandardError:[NSPipe pipe]];
+	} else if (accumulatedStandardErrorData && !flag) {
+		[accumulatedStandardErrorData release];
+		accumulatedStandardErrorData = nil;
+		[self setStandardError:nil];
+	}
+}
+
+@synthesize successfulTerminationBlock;
+@synthesize abnormalTerminationBlock;
+
+- (NSFileHandle *)devNullFileHandle {
+	static NSFileHandle *devNullFileHandle;
+	static dispatch_once_t onceToken;
+	dispatch_once(&onceToken, ^{
+		devNullFileHandle = [[NSFileHandle fileHandleForWritingAtPath:@"/dev/null"] retain];
+	});
+	return devNullFileHandle;
+}
+- (void) nullifyStandardOutput {
+	[self setStandardOutput:[self devNullFileHandle]];
+}
+- (void) nullifyStandardError {
+	[self setStandardError:[self devNullFileHandle]];
+}
+
+#pragma mark Inherited methods
+
+- (id) init {
+	if ((self = [super init])) {
+		trimWhitespaceFromAccumulatedOutputs = YES;
+	}
+	return self;
+}
+
+- (void) launch {
+	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+	taskDidTerminateObserverToken = [nc addObserverForName:NSTaskDidTerminateNotification
+		object:self
+		queue:nil
+		usingBlock:^(NSNotification *notification) {
+			PRHTask *task = [notification object];
+			PRHTerminationBlock block = ([task terminationStatus] == 0)
+				? [task successfulTerminationBlock]
+				: [task abnormalTerminationBlock];
+			block(task);
+		}];
+
+	void (^startPipe)(BOOL, id, NSMutableData *, NSString *, NSString *) = ^void(BOOL flag, id pipe, NSMutableData *destination, NSString *tokenPropertyKey, NSString *errorPropertyKey){
+		if (flag) {
+			id token = [nc addObserverForName:NSFileHandleReadCompletionNotification
+				object:pipe
+				queue:nil
+				usingBlock:^(NSNotification *notification) {
+					NSFileHandle *fh = [notification object];
+					NSData *data = [[notification userInfo] objectForKey:NSFileHandleNotificationDataItem];
+					if (data) {
+						if ([data length] > 0) {
+							[destination appendData:data];
+							[fh readInBackgroundAndNotify];
+						} else {
+							//End of file.
+						}
+					} else {
+						NSNumber *errnoNum = [[notification userInfo] objectForKey:@"NSFileHandleError"];
+						NSError *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:[errnoNum intValue] userInfo:nil];
+						[self setValue:error forKey:tokenPropertyKey];
+					}
+				}];
+			[self setValue:token forKey:tokenPropertyKey];
+
+			if ([pipe respondsToSelector:@selector(fileHandleForReading)]) {
+				NSFileHandle *fh = [pipe fileHandleForReading];
+				[fh readInBackgroundAndNotify];
+			}
+		}
+	};
+
+	startPipe([self accumulatesStandardOutput], [self standardOutput], accumulatedStandardOutputData, @"standardOutputObserverToken", @"standardOutputReadError");
+	startPipe([self accumulatesStandardError], [self standardError], accumulatedStandardErrorData, @"standardErrorObserverToken", @"standardErrorReadError");
+
+	[super launch];
+}
+
+- (void) dealloc {
+	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+
+	if (taskDidTerminateObserverToken) {
+		[nc removeObserver:taskDidTerminateObserverToken];
+		[taskDidTerminateObserverToken release];
+	}
+	if (standardOutputObserverToken) {
+		[nc removeObserver:standardOutputObserverToken];
+		[standardOutputObserverToken release];
+	}
+	if (standardErrorObserverToken) {
+		[nc removeObserver:standardErrorObserverToken];
+		[standardErrorObserverToken release];
+	}
+
+	[accumulatedStandardOutputData release];
+	[accumulatedStandardErrorData release];
+	[standardOutputReadError release];
+	[standardErrorReadError release];
+
+	[successfulTerminationBlock release];
+	[abnormalTerminationBlock release];
+
+	[super dealloc];
+}
+
+@end

File PRHTaskTest/PRHTaskTest.xcodeproj/project.pbxproj

+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		31068CEE1447F01C00DFAECC /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 31068CED1447F01C00DFAECC /* Foundation.framework */; };
+		31068CF11447F01C00DFAECC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 31068CF01447F01C00DFAECC /* main.m */; };
+		31068CF51447F01C00DFAECC /* PRHTaskTest.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 31068CF41447F01C00DFAECC /* PRHTaskTest.1 */; };
+		31068CFD1447F02600DFAECC /* PRHTask.m in Sources */ = {isa = PBXBuildFile; fileRef = 31068CFC1447F02600DFAECC /* PRHTask.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		31068CE71447F01C00DFAECC /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+				31068CF51447F01C00DFAECC /* PRHTaskTest.1 in CopyFiles */,
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		31068CE91447F01C00DFAECC /* PRHTaskTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PRHTaskTest; sourceTree = BUILT_PRODUCTS_DIR; };
+		31068CED1447F01C00DFAECC /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+		31068CF01447F01C00DFAECC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		31068CF31447F01C00DFAECC /* PRHTaskTest-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PRHTaskTest-Prefix.pch"; sourceTree = "<group>"; };
+		31068CF41447F01C00DFAECC /* PRHTaskTest.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = PRHTaskTest.1; sourceTree = "<group>"; };
+		31068CFB1447F02600DFAECC /* PRHTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PRHTask.h; path = ../../PRHTask.h; sourceTree = "<group>"; };
+		31068CFC1447F02600DFAECC /* PRHTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PRHTask.m; path = ../../PRHTask.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		31068CE61447F01C00DFAECC /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				31068CEE1447F01C00DFAECC /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		31068CDE1447F01C00DFAECC = {
+			isa = PBXGroup;
+			children = (
+				31068CEF1447F01C00DFAECC /* PRHTaskTest */,
+				31068CEC1447F01C00DFAECC /* Frameworks */,
+				31068CEA1447F01C00DFAECC /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		31068CEA1447F01C00DFAECC /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				31068CE91447F01C00DFAECC /* PRHTaskTest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		31068CEC1447F01C00DFAECC /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				31068CED1447F01C00DFAECC /* Foundation.framework */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		31068CEF1447F01C00DFAECC /* PRHTaskTest */ = {
+			isa = PBXGroup;
+			children = (
+				31068CFB1447F02600DFAECC /* PRHTask.h */,
+				31068CFC1447F02600DFAECC /* PRHTask.m */,
+				31068CF01447F01C00DFAECC /* main.m */,
+				31068CF41447F01C00DFAECC /* PRHTaskTest.1 */,
+				31068CF21447F01C00DFAECC /* Supporting Files */,
+			);
+			path = PRHTaskTest;
+			sourceTree = "<group>";
+		};
+		31068CF21447F01C00DFAECC /* Supporting Files */ = {
+			isa = PBXGroup;
+			children = (
+				31068CF31447F01C00DFAECC /* PRHTaskTest-Prefix.pch */,
+			);
+			name = "Supporting Files";
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		31068CE81447F01C00DFAECC /* PRHTaskTest */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 31068CF81447F01C00DFAECC /* Build configuration list for PBXNativeTarget "PRHTaskTest" */;
+			buildPhases = (
+				31068CE51447F01C00DFAECC /* Sources */,
+				31068CE61447F01C00DFAECC /* Frameworks */,
+				31068CE71447F01C00DFAECC /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = PRHTaskTest;
+			productName = PRHTaskTest;
+			productReference = 31068CE91447F01C00DFAECC /* PRHTaskTest */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		31068CE01447F01C00DFAECC /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = 31068CE31447F01C00DFAECC /* Build configuration list for PBXProject "PRHTaskTest" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 31068CDE1447F01C00DFAECC;
+			productRefGroup = 31068CEA1447F01C00DFAECC /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				31068CE81447F01C00DFAECC /* PRHTaskTest */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		31068CE51447F01C00DFAECC /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				31068CF11447F01C00DFAECC /* main.m in Sources */,
+				31068CFD1447F02600DFAECC /* PRHTask.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		31068CF61447F01C00DFAECC /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+				COPY_PHASE_STRIP = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.6;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		31068CF71447F01C00DFAECC /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.6;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		31068CF91447F01C00DFAECC /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "PRHTaskTest/PRHTaskTest-Prefix.pch";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		31068CFA1447F01C00DFAECC /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = "PRHTaskTest/PRHTaskTest-Prefix.pch";
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		31068CE31447F01C00DFAECC /* Build configuration list for PBXProject "PRHTaskTest" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				31068CF61447F01C00DFAECC /* Debug */,
+				31068CF71447F01C00DFAECC /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		31068CF81447F01C00DFAECC /* Build configuration list for PBXNativeTarget "PRHTaskTest" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				31068CF91447F01C00DFAECC /* Debug */,
+				31068CFA1447F01C00DFAECC /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 31068CE01447F01C00DFAECC /* Project object */;
+}

File PRHTaskTest/PRHTaskTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata

+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:PRHTaskTest.xcodeproj">
+   </FileRef>
+</Workspace>

File PRHTaskTest/PRHTaskTest/PRHTaskTest-Prefix.pch

+//
+// Prefix header for all source files of the 'PRHTaskTest' target in the 'PRHTaskTest' project
+//
+
+#ifdef __OBJC__
+	#import <Foundation/Foundation.h>
+#endif

File PRHTaskTest/PRHTaskTest/PRHTaskTest.1

+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd 2011-10-13               \" DATE 
+.Dt PRHTaskTest 1      \" Program name and manual section number 
+.Os Darwin
+.Sh NAME                 \" Section Header - required - don't modify 
+.Nm PRHTaskTest,
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line. 
+.Nm Other_name_for_same_program(),
+.Nm Yet another name for the same program.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd This line parsed for whatis database.
+.Sh SYNOPSIS             \" Section Header - required - don't modify
+.Nm
+.Op Fl abcd              \" [-abcd]
+.Op Fl a Ar path         \" [-a path] 
+.Op Ar file              \" [file]
+.Op Ar                   \" [file ...]
+.Ar arg0                 \" Underlined argument - use .Ar anywhere to underline
+arg2 ...                 \" Arguments
+.Sh DESCRIPTION          \" Section Header - required - don't modify
+Use the .Nm macro to refer to your program throughout the man page like such:
+.Nm
+Underlining is accomplished with the .Ar macro like this:
+.Ar underlined text .
+.Pp                      \" Inserts a space
+A list of items with descriptions:
+.Bl -tag -width -indent  \" Begins a tagged list 
+.It item a               \" Each item preceded by .It macro
+Description of item a
+.It item b
+Description of item b
+.El                      \" Ends the list
+.Pp
+A list of flags and their descriptions:
+.Bl -tag -width -indent  \" Differs from above in tag removed 
+.It Fl a                 \"-a flag as a list item
+Description of -a flag
+.It Fl b
+Description of -b flag
+.El                      \" Ends the list
+.Pp
+.\" .Sh ENVIRONMENT      \" May not be needed
+.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
+.\" .It Ev ENV_VAR_1
+.\" Description of ENV_VAR_1
+.\" .It Ev ENV_VAR_2
+.\" Description of ENV_VAR_2
+.\" .El                      
+.Sh FILES                \" File used or created by the topic of the man page
+.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
+.It Pa /usr/share/file_name
+FILE_1 description
+.It Pa /Users/joeuser/Library/really_long_file_name
+FILE_2 description
+.El                      \" Ends the list
+.\" .Sh DIAGNOSTICS       \" May not be needed
+.\" .Bl -diag
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .El
+.Sh SEE ALSO 
+.\" List links in ascending order by section, alphabetically within a section.
+.\" Please do not reference files that do not exist without filing a bug report
+.Xr a 1 , 
+.Xr b 1 ,
+.Xr c 1 ,
+.Xr a 2 ,
+.Xr b 2 ,
+.Xr a 3 ,
+.Xr b 3 
+.\" .Sh BUGS              \" Document known, unremedied bugs 
+.\" .Sh HISTORY           \" Document history if command behaves in a unique manner

File PRHTaskTest/PRHTaskTest/main.m

+//
+//  main.m
+//  PRHTaskTest
+//
+//  Created by Peter Hosey on 2011-10-13.
+//  Copyright 2011 Peter Hosey. All rights reserved.
+//
+
+#import "PRHTask.h"
+
+int main (int argc, char **argv) {
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+	PRHTask *task = [[[PRHTask alloc] init] autorelease];
+	[task setLaunchPath:@"/usr/bin/true"];
+	[task launch];
+
+	[pool drain];
+	return EXIT_SUCCESS;
+}
+