$HOME directory, plus the /Applications directory. There's probably other stuff that should be snarfed (like /Library), but I didn't on my last backup, and doing a restore from scratch seemed to work OK. Here's a quick outline of backing up to the external firewire drive called "Wikkit":
% sudo mkdir /Volumes/Wikkit/backup
% cd /Users
% sudo hfstar cf - bork | (cd /Volumes/Wikkit/backup; sudo hfstar xf -)
To Restore:
% cd /Users
% sudo mv bork bork-orig
% cd /Volumes/Wikkit/backup
% sudo hfstar cf - bork | (cd /Users; sudo hfstar xf -)
Some folks have had success with psync, but we haven't used it yet.
% cd /Users/bork/development/cool stuff/neat things
The other is to use shell completion to put in the backslashes for you. In
the above path, if you type
% cd /Users/bork/development/cool[tab], it'll expand
"cool stuff" for you.
% ~/bin/rename.pl 's/.oop$/.ack/' *.oop
To tack on an extension to all files, do something like
% ~/bin/rename.pl 's/(.*)/$1.jpg/' *
% perl -pi -e 's/
/
/g' mealcsv.csv
% cd /Users/bork/Library/Screen Savers
or you can surround it with quotes:
% cd "/Users/bork/Library/Screen Savers"
Note that tilde expansion (~/Library) is suppressed if you use the quotes.
% du -sk dir_name
To see how much each of a directory's contents consume, use
% du -sk dir_name/* | sort -n
to get a list ordered by size.
% cd directory
% find . -name "*.h" -exec grep NSDoWhatIMean {} ; -print{} construct. Also make sure there's a space after the {} and ;
% find . -type f -perm +06000 -print
(or use find / to start looking from the root directory.
% grep -c "fix me" *.m
% curl -O http://borkware.com/quickies/files/fullscreensaver.tar.gz
-l (dash ell) flag to grep. If a file contains the expression, the name of the file (rather than the matching line) is displayed.
e.g. to open all the files that contain 'rzolf'
% grep -l rzolf *.ham | xargs open
% rm -- -i-am-a-bad-file
% perl -pi.bak -e 's/OLDSTRING/NEWSTRING/g' *.html
% find . -type f -name "*.html" -exec grep Spoon {} ; -print
% sudo sh -c "tar cf - * | (cd /mirror4/web; tar xf -)"
cp -R is generally unsafe to copy directories with since it will copy through symbolic links rather than just copying the link (newer cp's have an -H flag that will work around this). The classic unix way of doing things like this is a push-pull tar:
% tar cf - dir-name | (cd /destination-dir; tar xf -)
In English: tar out through a pipe into a subshell that's changed directories, feeding that pipe into the tar extraction. If you run both sides of the pipeline as root (via sudo), the file owners and permissions will be preserved (which cp won't do)
% gcc -v --help
% tail -f /var/tmp/console.log
ppid option with the -o flag:
% ps -axo user,pid,ppid,vsz,tt,state,start,time,command
% find . ( -name "*.jpg" -o -name "*.gif" ) -exec do_something_wih {} ;
% identify filename.jpg
If you want to be studly, you can use -format to tailor
the output
% identify -format "insert into bw_graphics values (generate_primary_key(), '/images/llamas/%f', %w, %h);" *.jpg
generates a sql insert statement for each image.
% find . -name "*.jpg" -exec convert -verbose -geometry 150x150 {} {} ;
% ssh-keygen -t rsa
% scp ~/.ssh/id_rsa.pub gitdown.com:
% mv ~/id_rsa.pub ~/.ssh/authorized_keys
mv: rename build/ to oopack: Is a directorywhen using
mv or ln on the command line, that's a Darwin error. To correct the problem, remove the trailing slash from the directory name.
% hdid ram://size
where size is the size in bytes. the system will round that number up or down as it sees fit.
chflags in Mac OS X works like chattr over in Linux-land. So to make a file immutable (can't change it, even if you're the superuser), you can sudo chflags uchg file-name(s). To undo it, do sudo chflags nouchg file-name(s)
# niutil -create . /machines/tower # niutil -createprop . /machines/tower ip_address 10.0.1.155 # niutil niutil -createprop . /machines/tower serves ./local
/System/Library/StartupItems/SystemTuning/SystemTuningtweak some values, like
sysctl -w kern.sysv.shmmax=167772160 # bytes: 160 megs sysctl -w kern.sysv.shmmin=1 sysctl -w kern.sysv.shmmni=32 sysctl -w kern.sysv.shmseg=8 sysctl -w kern.sysv.shmall=65536 # 4k pages: 256 megsSave, and restart your system.
BWNagType.h:23: `BWConcreteType' defined as wrong kind of tag
In this particular case, I had a type I had declared with:
@class BWConcreteType;
and later on I had decided to turn it into an enum:
typedef enum BWConcreteType { ... } BWConcreteType;
without removing the previous @class declaration. So be on the look out for conflicting types for the same symbol.
pbxbuild. We've got a rant about cocoa development in emacs, which includes a discussion of pbxbuild.
/Developer/ProjectBuilder Extras/Project Templates/ and edit the projects there. The changes will take effect next time you create a new project.
Project->New Group. Give it a name. Note that the hierarchy of files in Project Builder is a fantasy of the project, and doesn't necessarily reflect what's actually in the file system.
WARNING_CFLAGS. Edit that, and add -Werror to what's already there.
blah.M (upper case M), or name your source file blah.mm (two lower case Ms)
if ([NSBundle loadNibNamed: @"theNibName.nib" owner: self]) {
... life is happy
} else {
... couldn't load the nib
}
Localizable.string, your NSLocalizedString() call will not look up the strings in the file. To verify the file, do something like this:
% pl < Localizable.strings
gdb There are two ways to enable core files:
% limit coredumpsize unlimited.cshrc. I don't know what to do for bash)
struct rlimit corelimit = { RLIM_INFINITY, RLIM_INFINITY };
setrlimit (RLIMIT_CORE, &corelimit);
You may need to also add#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
Core files seem to be getting dumped into /cores, rather than the directory the program was run from.
/System/Library/Frameworks/Foundation.framework/Headers/NSDebug.h. Lots of low-level unsupported APIs for mucking around with gory technical details.
fprintf
(gdb) thread apply all where
(gdb) fb -[NSTextView drawRect:]
(gdb) handle SIGTRAP nostop
The signal still goes to your program. Another handy option is 'ignore' to prevent it coming to the program. Also there is 'print' to print a message go on.
info selectors will show you all of the selectors in the application's symbol table. info funcitons will show you all of the functions. You can supply regular expressions to limit the output.
.emacs file:(global-set-key "C-Z" nil)
(setq c-default-style "bsd"
c-basic-offset 4)
#define DONT_REOPEN_PTY
!$). M-x dirs will tell the shell buffer to figure out what the current working directory is.
- Revisiting / reloading a file in emacs (emacs->General)
The $Id: $ tags for CVS are nice, but it can be a pain when you're doing lots of checkins and have to re-load the file each time. You can either execute M-x revert-bufer or bind that to a key, or else use a trick by doing C-x C-v which invokes find-alternate-file, but just so happens to have the current buffer name, so you just have to do C-x C-v RET
- Scroll line with cursor to the top of the window (emacs->General)
C-U 0 C-L
(you can put in another number besides zero to scroll the line with the cursor to that particular line in the buffer)
- Showing current column position (emacs->General)
M-x column-number-mode
- Toggling read-only mode in a buffer (emacs->General)
C-X C-Q
- Turning off command highlighting in shell mode (emacs->General)
Emacs 21, which comes with Mac OS X 10.2, "helpfully" puts into bold the commands you execute in the shell. This drives me nuts, so I figured out how to turn it off. Add this to your .emacs file:
(setq comint-highlight-input nil)
- Turning off incremental-search highlighting (emacs->General)
Emacs 21, which comes with Mac OS X 10.2, has highlighting enabled when doing incremental search (which drives me nuts). You can turn that off by setting this in your .emacs file:
(setq search-highlight nil)
You may also need to
(setq isearch-lazy-highlight nil)
To turn off underlining of matching results. Only some OS X installs need this setting.
- Undo within a given region (emacs->General)
C-U C-_
- Use only spaces when indenting code (emacs->General)
(setq indent-tabs-mode nil)
- Using carriage returns in query-replace / replace-string (emacs->General)
Use C-Q C-J (control-Q control-J) each time you want to include a carriage return. e.g. to double-space everything
M-x replace-string RET C-Q C-J RET C-Q C-J C-Q C-J RET
Or to put "bloogie " at the beginning of every line
M-x replace-string RET C-Q C-J RET C-Q C-J b l o o g i e SPACE RET
- Help! My Sheet won't go away (NSWindow->General)
You may need to call [sheet close] in addition to your [NSApp endSheet: sheet returnCode:23]
- Making a floating palette (NSWindow->General)
To make a floating palette with small controls, make the palette an NSPanel, and n IB make it a "Utility Window".
- I want my window's background to be yellow (NSWindow->Hacks)
Why you'd want to do that, I don't know, but someone asked me how to turn the window background yellow. Since the window has a contentView NSView in it, this adds a category on it that draws the background with a transparent yellow. You also get the pinstripe effects. Just put this code anywhere.
@implementation NSView (BWYellowView)
- (void) drawRect: (NSRect) rect
{
NSColor *transparentYellow;
rect = [self bounds];
transparentYellow = [NSColor colorWithCalibratedRed: 1.0
green: 1.0
blue: 0.0
alpha: 0.333];
[transparentYellow set];
[NSBezierPath fillRect: rect];
} // rect
@end // BWYellowView
I have no idea how you colorize the titlebar.
- Forwarding key events to another window (NSWindow->Random)
To forward key events to another window, make subclass of NSWindowsendEvent :
- (void) sendEvent: (NSEvent *) anEvent
{
if ([anEvent type] == NSKeyDown) {
[someOtherWindow sendEvent: anEvent];
} else {
[super sendEvent: anEvent];
}
} // sendEvent
It's up to you to figure out what "someOtherWindow" is, whether it's a delegate or an instance variable that holds the other window.
NSPoint point = [self convertPoint: [event locationInWindow] fromView: nil];
- (BOOL) _hasEditableCell
{
return (YES);
} // _hasEditableCell
This workaround is necessary at least for Mac OS X 10.1.*.
~/Library/Application Support/Chimera/Profiles/default/xyz.slt/prefs.js file:
user_pref("browser.urlbar.autocomplete.enabled", false);
NSString has a couple of convenience functions for print out basic structures like NSRect and NSSize:
NSStringFromRect (someNSRect);
NSStringFromPoint (someNSPoint);
NSStringFromSize (someNSSize);
#importint main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; [pool release]; } // main
And you can compile it on the command line with:
cc -o test -framework Foundation file-name.m
logo.jpg)
logo.jpg that's on the thingie drive
logo.jpg file/Developer/Tools/SetFile -a V /Volumes/thingie/logo.jpg
Image->Convert Image will let you compress the image. As a side-effect, this makes the image read-only.
NSBundle *bundle;
NSString *path;
bundle = [NSBundle bundleForClass: [self class]];
path = [bundle pathForResource: @"atomsymbol" ofType: @"jpg"];
image = [[NSImage alloc] initWithContentsOfFile: path];
Targets pane in Project Builder
Build Settings tab
Product Name under General Settings
~/Library/Preferences/ByHost directory. The name of the file is the name that you pass to defaultsForModuleWithName:, followed by
.someBigNumber.plist.
So, on my machine,
userPrefs = [ScreenSaverDefaults defaultsForModuleWithName: @"BWDrip"];creates a file
/Users/bork/Library/Preferences/ByHost/BWDrip.0003931024a6.plist
% /System/Library/Frameworks/ScreenSaver.framework/Resources/ScreenSaverEngine.app/Contents/MacOS/ScreenSaverEngine -background &
(all one command)
- (void) handleTimer: (NSTimer *) timer
{
do some work here...
} // handleTimer
NSTimer *timer;
timer = [NSTimer scheduledTimerWithTimeInterval: 0.5
target: self
selector: @selector(handleTimer:)
userInfo: nil
repeats: YES];
defaults = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithFloat: 25.0], @"density",
[NSNumber numberWithFloat: 40.0], @"rate",
nil];
% cvs admin -kb filename
cvswrappers file provided in the devtools. The easiest thing to do is to copy it to your homedir and prepend a dot:
% cp /Developer/Tools/cvswrappers ~/.cvswrappers
You can also add the contents of that fike to your repository.
.pbproj files aren't handled by the cvswrappers by default. You'll need to add a line like this:
*.pbproj -k 'b' -f '/Developer/Tools/cvs-unwrap %s' -t '/Developer/Tools/cvs-wrap %s %s' -m 'COPY'
% cvs checkout -D "3 days ago" blork
Or via a date (month/day/year)
% cvs checkout -D "10/17/2002" fnord
or recently in time
% cvs diff -D "1 hour ago" ook.blah
% cvs update -d [whatever]
% cvs log -r1.2:1.5 multiprocessing.txt
NSURL *url;
NSData *data;
NSImage *blork;
url = [NSURL URLWithString: @"http://borkware.com/hacks/random-pic"];
data = [url resourceDataUsingCache: NO];
blork = [[NSImage alloc] initWithData: data];
NSURL *url;
NSData *data;
NSString *blork;
url = [NSURL URLWithString: @"http://borkware.com/hacks/random"];
data = [url resourceDataUsingCache: NO];
blork = [[NSString alloc] initWithData: data encoding: NSASCIIStringEncoding];
NSWindow *grabWindow;
NSView *grabbedContentView;
NSBitmapImageRep *screenBits;
NSRect mainScreenBounds;
NSImage *screenImage;
mainScreenBounds = [[NSScreen mainScreen] frame];
grabWindow = [[NSWindow alloc] initWithContentRect: mainScreenBounds
styleMask: NSBorderlessWindowMask
backing: NSBackingStoreRetained
defer: NO
screen: nil];
[grabWindow setAlphaValue: 0.0];
[grabWindow setLevel: NSPopUpMenuWindowLevel];
[grabWindow orderWindow: NSWindowAbove relativeTo: 0];
grabbedContentView = [grabWindow contentView];
[grabbedContentView lockFocus];
screenBits = [[NSBitmapImageRep alloc] initWithFocusedViewRect: mainScreenBounds];
[grabbedContentView unlockFocus];
screenImage = [[NSImage alloc] initWithSize: mainScreenBounds.size];
[screenImage addRepresentation: screenBits];
[grabWindow close];
NSTableView's -setDoubleAction: method, and supply it a standard IBAction-style method selector.
You may need to also do -setTarget:. double-clicks get sent if the column isn't editable, so you may need to grab the column and do a -setEditable: NO on it.
% createlang plpgsql template1
% pg_dump databasename > db.out
pg_hba.conf, you can connect to the database, logged in as an ordinary person, by doing
% psql -U nsadmin opeancs
% createdb database-name
psql=# create user bork with password 'bork';
You can also do this for a passwordless user:
% crateuser bork
psql=# select to_timestamp('10:45am', 'HH12:MIam')::timetz::time;
to_timestamp
--------------
10:45:00
(1 row)
limit" statement:
select stuff from some_table where stuff.blah > 12 limit 5
% psql database-name user-name
% psql -h tower borkdb nettest
% pg_ctl -D /usr/local/pgsql/data -l /tmp/pgsql.log start
% psql -d databasename -f db.out
% psql -l
random() function.
select stuff.src, stuff.width, stuff.height from
(select src, width, height,
random()
from bw_eyes
order by 4) stuff
limit 1
This selects a random row from bw_eyes and returns the interesting data from it. This query is used on the quickies pages to randomly select an image of eyes staring back.
select current_timestamp()::date - entry_date::date as days_old from kb_nuggets;
shared_buffers in your postgresql.conf, and get an error similar to this:
IpcMemoryCreate: shmget(key=5432001, size=266371072, 03600) failed:
Invalid argument
This error usually means that PostgreSQL's request for a shared memory
segment exceeded your kernel's SHMMAX parameter.
You should increase your the shmmax parameters using tips in the Unix administration quickies.
- Darwin Website (Darwin->General)
Since I can never remember this, it's at developer.apple.com/darwin.
- Darwin's CVSROOT string (Darwin->CVS)
for read-only checkouts:
setenv CVSROOT :pserver:username@anoncvs.opensource.apple.com:/cvs/Darwin
- Appending to the end of a textview (NSTextView->General)
NSRange range;
range = NSMakeRange ([[textView string] length], 0);
[textView replaceCharactersInRange: range withString: string];
- Deleting the selected text (NSTextView->General)
[textView delete: nil]
- Forcing validation of pending text field entries (NSTextView->General)
[window makeFirstResponder: window]
- Moving insertion point to the end (NSTextView->General)
NSRange range = { [[textView string] length], 0 };
[textView setSelectedRange: range];
- Moving insertion point to the start (NSTextView->General)
NSRange zeroRange = { 0, 0 };
[textView setSelectedRange: zeroRange];
- Restricting typed in text to just digits (NSTextView->General)
Create a subclass of NSNumberFormatter, add this method, and hook up the formatter to your text fields.
- (BOOL) isPartialStringValid: (NSString **) partialStringPtr
proposedSelectedRange: (NSRangePointer) proposedSelRangePtr
originalString: (NSString *) origString
originalSelectedRange: (NSRange) origSelRange
errorDescription: (NSString **) error
{
NSCharacterSet *nonDigits;
NSRange newStuff;
NSString *newStuffString;
nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
newStuff = NSMakeRange(origSelRange.location,
proposedSelRangePtr->location
- origSelRange.location);
newStuffString = [*partialStringPtr substringWithRange: newStuff];
if ([newStuffString rangeOfCharacterFromSet: nonDigits
options: NSLiteralSearch].location != NSNotFound) {
*error = @"Input is not an integer";
return (NO);
} else {
*error = nil;
return (YES);
}
} // isPartialStringValid
- scrolling to the beginning of a textview (NSTextView->General)
NSRange zeroRange = { 0, 0 };
[textView scrollRangeToVisible: zeroRange];
- Scrolling to the end of a textview (NSTextView->General)
NSRange range;
range = NSMakeRange ([[textView string] length], 0);
[textView scrollRangeToVisible: range];
I've heard that scrollRangeToVisible is O(N) for the length of the text. So be on the lookout if you have lots of text involved.
- Changing checkbox toggle state (NSControl->General)
[myCheckbox setState: NSOffState]
NSOnState also works.
- Converting string to an integer (NSString->General)
NSString *string = ...;
Similarly, there is a floatValue and doubleValue NSString methods.
NSlog puts too much crud in front of the logging line. For a foundation tool that output stuff, it gets in the way. I'd still like for a replacement to expand %@, which the printf() family won't do. Here's a some code that'll do that.
#include <stdarg.h>
void LogIt (NSString *format, ...)
{
va_list args;
va_start (args, format);
NSString *string;
string = [[NSString alloc] initWithFormat: format arguments: args];
va_end (args);
printf ("%s\n", [string cString]);
[string release];
} // LogIt
NSRange range = [[string name] rangeOfString: otherString options: NSCaseInsensitiveSearch];
- (NSWindow *) window
{
NSArray *windowControllers;
windowControllers = [self windowControllers];
NSWindowController *controller;
controller = [windowControllers objectAtIndex: 0];
NSWindow *window;
window = [controller window];
return (window);
} // window
keepBackupFile:
- (BOOL) keepBackupFile
{
return (YES);
} // keepBackupFile
This will do the tilde thing to the older version of the file.
validateMenuItem: and do something like this:
- (BOOL) validateMenuItem: (id) menuItem { int result = YES; if ([menuItem action] == @selector(deleteNote:)) { if ([notes count] == 1) { result = NO; // can't delete the last note } } else if ([menuItem action] == @selector(gotoNote:)) { if ([notes count] == 1) { result = NO; // can't go to a different not if only one } } return (result); } // validateMenuItem
NSMenuWillSendActionNotification is posted to the notification center before the action is invoked.
gettimeofday() to get sub-second granularity for timing:#include <sys/time.h> struct timeval start, end; ... gettimeofday (&start, NULL); ... the code you're timing gettimeofday (&end, NULL); double fstart, fend; fstart = (start.tv_sec * 1000000.0 + start.tv_usec) / 1000000.0; fend = (end.tv_sec * 1000000.0 + end.tv_usec) / 1000000.0; NSLog (@"it took %f seconds", fend - fstart);
- (void) awakeFromNib
{
[browser setTarget: self];
[browser setDoubleAction: @selector(browserDoubleClick:)];
} // awakeFromNib
...
- (IBAction) browserDoubleClick: (id) sender
{
int column = [browser selectedColumn];
int row = [browser selectedRowInColumn: column];
// then dig into your data tructure with the row and column
} // browserDoubleClick
NSString *filename = @"/my/original/file/name";
NSString *tildeFilename;
tildeFilename = [NSString stringWithFormat: @"%@~", filename];
// remove it first, otherwise the move will fail
[defaultManager removeFileAtPath: tildeFilename
handler: nil];
// now rename the file
[defaultManager movePath: filename
toPath: tildeFilename
handler: nil];
NSString *filename = @"/this/is/my/file/path";
NSFileManager *defaultManager;
defaultManager = [NSFileManager defaultManager];
NSData *data;
data = [defaultManager contentsAtPath: filename];
NSFileManager *defaultManager;
defaultManager = [NSFileManager defaultManager];
[defaultManager removeFileAtPath: tildeFilename
handler: nil];
The handler is an object that will be sent message, like fileManager:shouldProceedAfterError: if something goes wrong during the removal.
NSString *filename = @"/this/is/my/file/name";
NSData *data = // get NSData from somewhere, like NSPropertyListSerialization
NSFileManager *defaultManager;
defaultManager = [NSFileManager defaultManager];
// either remove or rename the existing file using NSFileManager
[defaultManager createFileAtPath: filename
contents: data
attributes: nil];
NSData *data = // get NSData from somewhere, like NSFileManager
if (data) {
myRootObject = [NSPropertyListSerialization
propertyListFromData: data
mutabilityOption: NSPropertyListMutableContainers
format: nil
errorDescription: nil];
}
For the mutability options of the resulting object, you can also use NSPropertyListImmutable and NSPropertyListMutableContainersAndLeaves
NSDictionary, NSArray,NSNumber, NSString, NSData) as XML like this:
NSData *data;
data = [NSPropertyListSerialization
dataFromPropertyList: notes
format: NSPropertyListXMLFormat_v1_0
errorDescription: nil];
Then write out the data using NSFileManager, or whatever other mechanism you wish.
- (id) initWithCoder: (NSCoder *) aDecoder
{
if (self = [super init]) {
// or else [super initWithCoder: aDecoder] if your superclass
// supports it. NSObject does not.
// decoding a C type
[aDecoder decodeValueOfObjCType: @encode(int)
at: &itemCount];
// decoding an array of C structs
if (items != NULL) {
free (items);
}
items = malloc (sizeof(BWRawPathItem) * itemCount);
int i;
for (i = 0; i < itemCount; i++) {
[aDecoder decodeValueOfObjCType: @encode(BWRawPathItem)
at: &items[i]];
}
// decoding an object
name = [aDecoder decodeObject];
[name retain];
// any other random initializations that don't come from
// the encoder
fooby = -1;
}
[self retain];
return (self);
} // initWithCoder
- (void) encodeWithCoder: (NSCoder *) aCoder
{
// [super encodeWithCoder:] if you inherit from a class
// that supports encoding. NSObject does not.
// encoding a C type
[aCoder encodeValueOfObjCType: @encode(int)
at: &itemCount];
// encoding an array of C structs
int i;
for (i = 0; i < itemCount; i++) {
[aCoder encodeValueOfObjCType: @encode(BWRawPathItem)
at: &items[i]];
}
// encoding an object
[aCoder encodeObject: name];
} // encodeWithCoder
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/ls"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-l", @"-a", @"-t", nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
NSLog (@"woop! got\n%@", string);
Of course, you can use different NSFileHandle methods for different styles of reading, and you can make a pipe for standard input so you can feed data to the task.
NSTasks and a bunch of NSPipes and hook them together, or you can use the "sh -c" trick to feed a shell a command, and let it parse it and set up all the IPC. This pipeline cats /usr/share/dict/words, finds all the words with 'ham' in them, reverses them, and shows you the last 5.
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: @"-c",
@"cat /usr/share/dict/words | grep -i ham | rev | tail -5", nil];
[task setArguments: arguments];
// and then do all the other jazz for running an NSTask.
- (NSString*) title
{
return (title);
} // title
- (void) setTitle: (NSString *) newTitle
{
[title autorelease];
title = [newTitle copy];
} // setTitle
For maximum safety (this is thread safe too), use this:
- (NSString *) title
{
return [[title retain] autorelease];
} // title
- (void) setTitle: (NSString *) newTitle
{
if (title != newtitle) {
[title release];
title = [newTitle copy];
}
} // setTitle
NSColor you used was created in Device space (e.g. colorWithDeviceRed:green:blue:alpha:) If you use a Calibrated color (colorWithCalibratedRed:green:blue:alpha:), the triangle goes away.