Header File: BJGOptionInterpreter.h
//
// BJGOptionInterpreter.h
// Escape
//
// Created by Brent Gulanowski on 11/26/05.
// Copyright 2005 Bored Astronaut Software. All rights reserved.
//
// Parses options which follow the “-<option_letter> [option_arg] [-<option_letter> …] [other_arg …]” style#import <Foundation/Foundation.h>
@interface BJGOptionInterpreter : NSObject {
NSString *optionList;
NSString *executable;
NSDictionary *options;
NSArray *arguments;
}/* for format of opts, see “man 3 getopt”; args is an array of strings: launch arguments */
-(id)initWithOptionList:(NSString *)opts rawArguments:(NSArray *)args;-(NSString *)optionList;
-(NSString *)executable;
-(NSDictionary *)options;
-(NSArray *)arguments;
@end
Source: BJGOptionInterpreter.h
Implementation File: BJGOptionInterpreter.m
//
// BJGOptionInterpreter.m
// Escape
//
// Created by Brent Gulanowski on 11/26/05.
// Copyright 2005 Bored Astronaut Software. All rights reserved.
//#import “BJGOptionInterpreter.h”
#import <unistd.h>
@interface BJGOptionInterpreter (BJGOptionInterpreter_private)
+(NSArray *)parseOptions:(NSString *)opts;
@end@implementation BJGOptionInterpreter
/** inheritance tree overrides **/
#pragma mark NSObject
#if 0 /* remove the guards as necessary */
+(void)initialize {
}
#endif-(id)init {
[self release];
return nil;
}/** new methods **/
#pragma mark BJGOptionInterpreter-(id)initWithOptionList:(NSString *)optList rawArguments:(NSArray *)args {
NSArray *allOpts = [BJGOptionInterpreter parseOptions:optList];
NSMutableArray *opts = [NSMutableArray array];
NSMutableArray *optsArgs = [NSMutableArray array]; /* “opt_s_Args” plural: array of arrays of args */
NSMutableArray *otherArgs = [NSMutableArray array];
NSEnumerator *argsEnumerator;
id arg;
id nextArg;
if(nil == args) {
args = [[NSProcessInfo processInfo] arguments];
}
argsEnumerator = [args objectEnumerator];executable = [argsEnumerator nextObject];
arg = [argsEnumerator nextObject];
nextArg = [argsEnumerator nextObject];while(arg) {
id option;
id optionWithArgs;
/* If the current arg doesn’t look like an option… */
if(’-’ != [arg characterAtIndex:0] /*|| 2 != [arg length]*/) {
/* it isn’t … */
[otherArgs addObject:arg];
/* … and none of the rest are either */
if(nextArg) {
do {
[otherArgs addObject:nextArg];
} while(nextArg = [argsEnumerator nextObject]);
}
break;
}/* It may look like an option, but we have to confirm it’s legitimate */
option = [arg substringWithRange:NSMakeRange(1,1)];optionWithArgs = [option stringByAppendingString:@”:”];
/* a legit option without arguments */
if(YES == [allOpts containsObject:option]) {
int argLength = [arg length];
int pos = 2;
if(NO == [opts containsObject:option]) {
[opts addObject:option];
[optsArgs addObject:[NSArray array]];
}
while(argLength - pos > 0 && YES == [allOpts containsObject:option]) {
option = [arg substringWithRange:NSMakeRange(pos++,1)];
if(NO == [opts containsObject:option]) {
[opts addObject:option];
[optsArgs addObject:[NSArray array]];
}
}
}
else if(YES == [allOpts containsObject:optionWithArgs]) {
/* a legit option with arguments */
NSMutableArray *optionArgs = [NSMutableArray array]; /* array of args */
if([arg length] > 2) {
[optionArgs addObject:[arg substringFromIndex:2]];
}
/* collect the arguments */
while(nextArg && ‘-’ != [nextArg characterAtIndex:0]) {
[optionArgs addObject:nextArg];
nextArg = [argsEnumerator nextObject];
}
/* opts that require args and don’t have ‘em mean an error */
if(0 == [optionArgs count]) {
[self release];
self = nil;
break;
}
/* have we seen this option already? if so, coalesce arguments */
if(YES == [opts containsObject:option]) {
int originalOptionIndex = [opts indexOfObject:option];
[optionArgs addObjectsFromArray:[optsArgs objectAtIndex:originalOptionIndex]];
[optsArgs replaceObjectAtIndex:originalOptionIndex withObject:optionArgs];
}
else {
[opts addObject:option];
[optsArgs addObject:optionArgs];
}
}
/* bad option; release self and return nothing; app should print usage message */
else {
[self release];
self = nil;
break;
}
arg = nextArg;
nextArg = [argsEnumerator nextObject];
}
/* if we got here and didn’t commit suicide, collect a nice arg dictionary */
if(self) {
optionList = [optList retain];
arguments = [[NSArray arrayWithArray:otherArgs] retain];
options = [[NSDictionary dictionaryWithObjects:optsArgs forKeys:opts] retain];
}return self;
}-(NSString *)optionList {
return [[optionList copy] autorelease];
}-(NSString *)executable {
return [[executable copy] autorelease];
}-(NSDictionary *)options {
return [[options copy] autorelease];
}-(NSArray *)arguments {
return [[arguments copy] autorelease];
}#pragma mark BJGOptionInterpreter_private
+(NSArray *)parseOptions:(NSString *)opts {
int i;
int length =[opts length];
NSMutableArray *options = [NSMutableArray arrayWithCapacity:length];
NSCharacterSet *lower = [NSCharacterSet lowercaseLetterCharacterSet];
for(i = 0; ichar current = [opts characterAtIndex:i];
char next;
if(i < length - 1) {
next = [opts characterAtIndex:i+1];
}
else {
next = '\0';
}
if(NO == [lower characterIsMember:current]) {
continue;
}
NSString *option = [NSString stringWithCString:¤t length:1];
if(':' == next) {
option = [option stringByAppendingString:@":"];
i++;
}
if(NO == [options containsObject:option]) {
[options addObject:option];
}
}
return [NSArray arrayWithArray:options];
}@end
Source Code: BJGOptionInterpreter.m