Mac OS X Command Line Application Development

A few quick notes:

  • When creating a new app, be sure to select “Foundation” for the type. This brings into the fold all of the common classes like NSString, NSArray, and other classes already familiar from using Foundation via Cocoa.
  • Use ARC (automatic reference counting/garbage collection) to save a lot of hassle. This adds an @autoreleasepool{} clause in main() but that’s a small price to pay for the convenience.
  • The implementation file needs to be handled the same way as any other C file, with either functions implemented before main() or function prototypes declared.

Beyond that, creating a command line app is just like working with Cocoa.

Converting between C and Objective-C Strings

This will come up when working with any arguments that are passed into main(). NSString has a couple of functions that will help manage all of the pointer references but encoding becomes an issue here.

int main(int argc, const char * argv[])
{
	@autoreleasepool {
		// char * to NSString
		NSString *foo = [NSString stringWithUTF8String:argv[1]];
		// NSString to char * (used in printf)
		printf( "%s\n", [foo cStringUsingEncoding:NSUTF8StringEncoding] );
	}
}

Functions

Functions for the command line need to be handled as they are with C just with Foundation classes

Objective-C/Cocoa version:

- (NSString *) foo:( NSString * )bar
{
    // do something
}

C version:

NSString * foo( NSString * bar )
{
    // do something
}

A complete example

Here is built a small tool that returns a coupled pair of uniquely identified HTML anchor links to facilitate the creation of footnotes, and to facilitate readability in long pages or posts. The first line is the superscript number pointing to the footnote, and the second line is a link to the main text from where the footnote is referenced. To wit…

$ anchor 00
<a id="1691795450988477538" href="#20976447639567818223"><sup>00</sup></a>
<a id="20976447639567818223" href="#1691795450988477538">&#x2934;</a>
$

Here is the intended use with the HTML; footnotes handled as an ordered list…

Here is some text with a reference.<a id="1691795450988477538" href="#20976447639567818223"><sup>1</sup></a>
<hr />
<ol>
	<li>Here is the reference. <a id="20976447639567818223" href="#1691795450988477538">&#x2934;</a></li>
</ol>

…and how it appears to the user.
Here is some text with a reference.1


  1. Here is the reference.

 

Here is how the coupled tags are built in the command line using Foundation. The first line is placed by Xcode automagically linking to the Foundation framework.

#import <Foundation/Foundation.h>

Next come the function prototypes. Like in C, functions have to be declared, as in a header, or actually implemented before main(). (For something this small, I wouldn’t use function prototypes normally).

// function prototypes
NSString * createFootnoteAnchors( NSString * text );
NSString * createUUID();

The main() function is the same as expected. Xcode adds in the @autoreleasepool {} clause automagically as well.

int main(int argc, const char * argv[])
{

@autoreleasepool {

if ( argc == 1 ) {
// no text is passed to wrap, just build the anchors with dummy text
NSString *anchors = createFootnoteAnchors( [NSString stringWithFormat:@"00"] );
printf( "%s\n", [anchors cStringUsingEncoding:NSUTF8StringEncoding] );

} else if ( argc == 2 ) {
// text is passed for us to wrap
NSString *anchors = createFootnoteAnchors( [NSString stringWithUTF8String:argv[1]] );
printf( "%s\n", [anchors cStringUsingEncoding:NSUTF8StringEncoding] );
} else {
// only one at a time, bub
printf( "usage: anchor [text]\n" );
return 1;
}

}
return 0;
}

Inside the ARC clause, the first interaction between C and Foundation/Objective-C can be found.

NSString *anchors = createFootnoteAnchors( [NSString stringWithUTF8String:argv[1] );
printf( "%s\n", [anchors cStringUsingEncoding:NSUTF8StringEncoding] );

NSString contains a variety of functions that allow for smooth conversion between C strings (char *) and NSString, and is where the power of Foundation comes into play. The first line grabs the first argument and converts from char * to NSString, and the second line reverses that conversion to be used in printf(). A more simplified version of the above would be this…

// char * to NSString
NSString *foo = [NSString stringWithUTF8String:argv[1]];
// NSString to char *
const char *bar = [foo cStringUsingEncoding:NSUTF8StringEncoding];

There is nothing to say that the work with arguments can’t remain in C; that is just a matter of the tool’s requirements relevant to one’s preferences. Beyond this, in main(), everything is same as it is with C, returning 0 upon successful completion.

Now we come to the core functions of the tool. Notice the difference here in that these are Foundation classes in a C format. If we were to write these functions for Cocoa, then they would be written thus…

- (NSString *) createFootnoteAnchors:(NSString *)text;
- (NSString *) createUUID;

Other than how the function is implemented, the code can be used verbatim with Cocoa.

/*
Returns a pair of coupled, uniquely id's anchors wrapped around a given string
*/
NSString * createFootnoteAnchors( NSString * text )
{
NSMutableString *anchors = [NSMutableString string];

NSString *textID = createUUID();
NSString *footnoteID = createUUID();

[anchors appendFormat:@"%@\n", footnoteID, textID, text];
[anchors appendFormat:@"\n", textID, footnoteID];

return [NSString stringWithString:anchors];
}

/*
Returns a string of what is expected to be a unique value
*/
NSString * createUUID()
{
NSString *uuid = [NSString stringWithFormat:@"%@", CFUUIDCreateString( NULL, CFUUIDCreate( NULL ) )];

// uuids are messy for this purpose; let's clean it up using Foundation classes

NSString *noDash = [uuid stringByReplacingOccurrencesOfString:@"-" withString:@""];
NSArray *tokens = [noDash componentsSeparatedByCharactersInSet:[NSCharacterSet uppercaseLetterCharacterSet]];

return [tokens componentsJoinedByString:@""];
}