XADMaster/CSCommandLineParser.m
2018-03-21 14:24:50 +02:00

855 lines
24 KiB
Objective-C

/*
* CSCommandLineParser.m
*
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#import "CSCommandLineParser.h"
#import "NSStringPrinting.h"
#ifdef __MINGW32__
#import <windows.h>
#endif
static NSString *NamesKey=@"NamesKey";
static NSString *AllowedValuesKey=@"AllowedValuesKey";
static NSString *DefaultValueKey=@"DefaultValueKey";
static NSString *OptionTypeKey=@"OptionType";
static NSString *DescriptionKey=@"DescriptionKey";
static NSString *ArgumentDescriptionKey=@"ArgumentDescriptionKey";
static NSString *AliasTargetKey=@"AliasTargetKey";
static NSString *RequiredOptionsKey=@"RequiredOptionsKey";
static NSString *NumberValueKey=@"NumberValue";
static NSString *StringValueKey=@"StringValue";
static NSString *ArrayValueKey=@"ArrayValue";
static NSString *StringOptionType=@"StringOptionType";
static NSString *MultipleChoiceOptionType=@"MultipleChoiceOptionType";
static NSString *IntegerOptionType=@"IntegerOptionType";
static NSString *FloatingPointOptionType=@"FloatingPointOptionType";
static NSString *SwitchOptionType=@"SwitchOptionType";
static NSString *HelpOptionType=@"HelpOptionType";
static NSString *VersionOptionType=@"VersionOptionType";
static NSString *AliasOptionType=@"AliasOptionType";
#if MAC_OS_X_VERSION_MAX_ALLOWED<1050
@interface NSScanner (BuildKludge)
-(BOOL)scanHexLongLong:(unsigned long long *)val;
-(BOOL)scanHexDouble:(double *)val;
@end
#endif
@implementation CSCommandLineParser
-(id)init
{
if((self=[super init]))
{
options=[NSMutableDictionary new];
optionordering=[NSMutableArray new];
alwaysrequiredoptions=[NSMutableArray new];
remainingargumentarray=nil;
programname=nil;
usageheader=nil;
usagefooter=nil;
programversion=nil;
}
return self;
}
-(void)dealloc
{
[options release];
[optionordering release];
[alwaysrequiredoptions release];
[remainingargumentarray release];
[programname release];
[usageheader release];
[usagefooter release];
[programversion release];
[super dealloc];
}
-(void)setProgramName:(NSString *)name
{
[programname autorelease];
programname=[name retain];
}
-(void)setUsageHeader:(NSString *)header
{
[usageheader autorelease];
usageheader=[header retain];
}
-(void)setUsageFooter:(NSString *)footer
{
[usagefooter autorelease];
usagefooter=[footer retain];
}
-(void)setProgramVersion:(NSString *)version
{
[programversion autorelease];
programversion=[version retain];
}
-(void)addStringOption:(NSString *)option
description:(NSString *)description
{
[self addStringOption:option defaultValue:nil description:description argumentDescription:@"string"];
}
-(void)addStringOption:(NSString *)option defaultValue:(NSString *)defaultvalue
description:(NSString *)description
{
[self addStringOption:option defaultValue:defaultvalue description:description argumentDescription:@"string"];
}
-(void)addStringOption:(NSString *)option
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self addStringOption:option defaultValue:nil description:description argumentDescription:argdescription];
}
-(void)addStringOption:(NSString *)option defaultValue:(NSString *)defaultvalue
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
StringOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
if(defaultvalue) [dict setObject:defaultvalue forKey:DefaultValueKey];
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
-(void)addMultipleChoiceOption:(NSString *)option allowedValues:(NSArray *)allowedvalues
description:(NSString *)description
{
[self addMultipleChoiceOption:option allowedValues:allowedvalues defaultValue:nil
description:description argumentDescription:[allowedvalues componentsJoinedByString:@"|"]];
}
-(void)addMultipleChoiceOption:(NSString *)option allowedValues:(NSArray *)allowedvalues defaultValue:(NSString *)defaultvalue
description:(NSString *)description
{
[self addMultipleChoiceOption:option allowedValues:allowedvalues defaultValue:defaultvalue
description:description argumentDescription:[allowedvalues componentsJoinedByString:@"|"]];
}
-(void)addMultipleChoiceOption:(NSString *)option allowedValues:(NSArray *)allowedvalues
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self addMultipleChoiceOption:option allowedValues:allowedvalues defaultValue:nil
description:description argumentDescription:argdescription];
}
-(void)addMultipleChoiceOption:(NSString *)option allowedValues:(NSArray *)allowedvalues defaultValue:(NSString *)defaultvalue
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
allowedvalues,AllowedValuesKey,
MultipleChoiceOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
if(defaultvalue)
{
NSUInteger index=[allowedvalues indexOfObject:[defaultvalue lowercaseString]];
if(index==NSNotFound) [NSException raise:NSInvalidArgumentException format:
@"Default value \"%@\" is not in the array of allowed values.",defaultvalue];
[dict setObject:[NSNumber numberWithUnsignedInt:index] forKey:DefaultValueKey];
}
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
-(void)addIntegerOption:(NSString *)option
description:(NSString *)description
{
[self addIntegerOption:option
description:description argumentDescription:@"integer"];
}
-(void)addIntegerOption:(NSString *)option
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
IntegerOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
-(void)addIntegerOption:(NSString *)option defaultValue:(int)defaultvalue
description:(NSString *)description
{
[self addIntegerOption:option defaultValue:defaultvalue
description:description argumentDescription:@"integer"];
}
-(void)addIntegerOption:(NSString *)option defaultValue:(int)defaultvalue
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
[NSNumber numberWithInt:defaultvalue],DefaultValueKey,
IntegerOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
// Int options with range?
-(void)addFloatingPointOption:(NSString *)option
description:(NSString *)description
{
[self addFloatingPointOption:option
description:description argumentDescription:@"number"];
}
-(void)addFloatingPointOption:(NSString *)option
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
FloatingPointOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
-(void)addFloatingPointOption:(NSString *)option defaultValue:(double)defaultvalue
description:(NSString *)description
{
[self addFloatingPointOption:option defaultValue:defaultvalue
description:description argumentDescription:@"number"];
}
-(void)addFloatingPointOption:(NSString *)option defaultValue:(double)defaultvalue
description:(NSString *)description argumentDescription:(NSString *)argdescription
{
[self _assertOptionNameIsUnique:option];
NSMutableDictionary *dict=[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
[NSNumber numberWithDouble:defaultvalue],DefaultValueKey,
FloatingPointOptionType,OptionTypeKey,
description,DescriptionKey,
argdescription,ArgumentDescriptionKey,
nil];
[options setObject:dict forKey:option];
[optionordering addObject:option];
}
-(void)addSwitchOption:(NSString *)option description:(NSString *)description
{
[self _assertOptionNameIsUnique:option];
[options setObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:option],NamesKey,
SwitchOptionType,OptionTypeKey,
description,DescriptionKey,
nil] forKey:option];
[optionordering addObject:option];
}
-(void)addHelpOption
{
[self addHelpOptionNamed:@"help" description:@"Display this information."];
[self addAlias:@"h" forOption:@"help"];
}
-(void)addHelpOptionNamed:(NSString *)helpoption description:(NSString *)description
{
[options setObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:helpoption],NamesKey,
HelpOptionType,OptionTypeKey,
description,DescriptionKey,
nil] forKey:helpoption];
[optionordering addObject:helpoption];
}
-(void)addVersionOption
{
[self addVersionOptionNamed:@"version" description:@"Print version and exit."];
[self addAlias:@"v" forOption:@"version"];
}
-(void)addVersionOptionNamed:(NSString *)versionoption description:(NSString *)description
{
[options setObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSMutableArray arrayWithObject:versionoption],NamesKey,
VersionOptionType,OptionTypeKey,
description,DescriptionKey,
nil] forKey:versionoption];
[optionordering addObject:versionoption];
}
-(void)addAlias:(NSString *)alias forOption:(NSString *)option
{
[self _assertOptionNameIsUnique:alias];
NSMutableDictionary *dict=[options objectForKey:option];
if(!dict) [self _raiseUnknownOption:option];
[[dict objectForKey:NamesKey] addObject:alias];
[options setObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:
option,AliasTargetKey,
AliasOptionType,OptionTypeKey,
nil] forKey:alias];
}
-(void)addRequiredOption:(NSString *)requiredoption
{
if(![options objectForKey:requiredoption]) [self _raiseUnknownOption:requiredoption];
[alwaysrequiredoptions addObject:requiredoption];
}
-(void)addRequiredOptionsArray:(NSArray *)requiredoptions
{
NSEnumerator *enumerator=[requiredoptions objectEnumerator];
NSString *requiredoption;
while((requiredoption=[enumerator nextObject])) [self addRequiredOption:requiredoption];
}
-(void)addRequiredOption:(NSString *)requiredoption forOption:(NSString *)option
{
NSMutableDictionary *dict=[options objectForKey:option];
if(!dict) [self _raiseUnknownOption:option];
NSMutableArray *requiredoptions=[dict objectForKey:RequiredOptionsKey];
if(requiredoptions) [requiredoptions addObject:requiredoption];
else
{
requiredoptions=[NSMutableArray arrayWithObject:requiredoption];
[dict setObject:requiredoptions forKey:RequiredOptionsKey];
}
}
-(void)addRequiredOptionsArray:(NSArray *)requiredoptions forOption:(NSString *)option
{
NSEnumerator *enumerator=[requiredoptions objectEnumerator];
NSString *requiredoption;
while((requiredoption=[enumerator nextObject])) [self addRequiredOption:requiredoption forOption:option];
}
-(BOOL)parseCommandLineWithArgc:(int)argc argv:(const char **)argv
{
NSMutableArray *arguments=[NSMutableArray array];
#ifdef __MINGW32__
int wargc;
wchar_t **wargv=CommandLineToArgvW(GetCommandLineW(),&wargc);
for(int i=1;i<wargc;i++) [arguments addObject:[NSString stringWithCharacters:wargv[i] length:wcslen(wargv[i])]];
if(!programname) [self setProgramName:[NSString stringWithCharacters:wargv[0] length:wcslen(wargv[0])]];
#else
for(int i=1;i<argc;i++) [arguments addObject:[NSString stringWithUTF8String:argv[i]]];
if(!programname) [self setProgramName:[NSString stringWithUTF8String:argv[0]]];
#endif
return [self parseArgumentArray:arguments];
}
-(BOOL)parseArgumentArray:(NSArray *)arguments
{
NSMutableArray *remainingarguments=[NSMutableArray array];
NSMutableArray *errors=[NSMutableArray array];
[self _parseArguments:arguments remainingArguments:remainingarguments errors:errors];
[self _setDefaultValues];
[self _parseRemainingArguments:remainingarguments errors:errors];
[self _enforceRequirementsWithErrors:errors];
if([errors count])
{
[self _reportErrors:errors];
return NO;
}
else return YES;
}
-(void)_parseArguments:(NSArray *)arguments remainingArguments:(NSMutableArray *)remainingarguments
errors:(NSMutableArray *)errors
{
NSEnumerator *enumerator=[arguments objectEnumerator];
NSString *argument;
BOOL stillparsing=YES;
while((argument=[enumerator nextObject]))
{
// Check for options, unless we have seen a stop marker.
if(stillparsing && [argument length]>1 && [argument characterAtIndex:0]=='-')
{
// Check for a stop marker.
if([argument isEqual:@"--"])
{
stillparsing=NO;
continue;
}
// See if option starts with one or two dashes (treated the same for now).
int firstchar=1;
if([argument characterAtIndex:1]=='-') firstchar=2;
// See if the option is of the form -option=value, and extract the name and value.
// Otherwise, just extract the name.
NSString *option,*value;
NSRange equalsign=[argument rangeOfString:@"="];
if(equalsign.location!=NSNotFound)
{
option=[argument substringWithRange:NSMakeRange(firstchar,equalsign.location-firstchar)];
value=[argument substringFromIndex:equalsign.location+1];
}
else
{
option=[argument substringFromIndex:firstchar];
value=nil; // Find the value later.
}
// Find option dictionary, or produce an error if the option is not known.
NSMutableDictionary *dict=[options objectForKey:option];
if(!dict)
{
[errors addObject:[NSString stringWithFormat:@"Unknown option %@.",argument]];
continue;
}
NSString *type=[dict objectForKey:OptionTypeKey];
// Resolve aliases.
while(type==AliasOptionType)
{
dict=[options objectForKey:[dict objectForKey:AliasTargetKey]];
type=[dict objectForKey:OptionTypeKey];
}
// Handle help options.
if(type==HelpOptionType)
{
[self printUsage];
exit(0);
}
// Handle version option
if(type==VersionOptionType)
{
[programversion print];
[@"\n" print];
exit(0);
}
// Find value for options of the form -option value, if needed.
if(!value)
if(type==StringOptionType||type==MultipleChoiceOptionType||
type==IntegerOptionType||type==FloatingPointOptionType)
{
value=[enumerator nextObject];
if(!value)
{
[errors addObject:[NSString stringWithFormat:@"The option -%@ requires a value.",option]];
continue;
}
}
// Actually parse value and type
[self _parseOptionWithDictionary:dict type:type name:option value:value errors:errors];
}
else
{
[remainingarguments addObject:argument];
}
}
}
-(void)_parseOptionWithDictionary:(NSMutableDictionary *)dict type:(NSString *)type
name:(NSString *)option value:(NSString *)value errors:(NSMutableArray *)errors
{
if(type==StringOptionType)
{
[dict setObject:value forKey:StringValueKey];
}
else if(type==MultipleChoiceOptionType)
{
NSArray *allowedvalues=[dict objectForKey:AllowedValuesKey];
NSUInteger index=[allowedvalues indexOfObject:[value lowercaseString]];
if(index==NSNotFound)
{
[errors addObject:[NSString stringWithFormat:@"\"%@\" is not a valid "
@"value for option \"%@\". (Valid values are: %@.)",value,option,
[allowedvalues componentsJoinedByString:@", "]]];
return;
}
[dict setObject:[allowedvalues objectAtIndex:index] forKey:StringValueKey];
[dict setObject:[NSNumber numberWithUnsignedInt:index] forKey:NumberValueKey];
}
else if(type==IntegerOptionType)
{
NSScanner *scanner=[NSScanner scannerWithString:value];
BOOL success;
if([value hasPrefix:@"0x"]||[value hasPrefix:@"0X"])
{
unsigned long long intval;
success=[scanner scanHexLongLong:&intval];
if(success) [dict setObject:[NSNumber numberWithUnsignedLongLong:intval] forKey:NumberValueKey];
}
else
{
long long intval;
success=[scanner scanLongLong:&intval];
if(success) [dict setObject:[NSNumber numberWithLongLong:intval] forKey:NumberValueKey];
}
if(!success)
{
[errors addObject:[NSString stringWithFormat:@"The option -%@ requires an "
@"integer number value.",option]];
return;
}
}
else if(type==FloatingPointOptionType)
{
NSScanner *scanner=[NSScanner scannerWithString:value];
double floatval;
BOOL success;
#ifndef __COCOTRON__
if([value hasPrefix:@"0x"]||[value hasPrefix:@"0X"]) success=[scanner scanHexDouble:&floatval];
else success=[scanner scanDouble:&floatval];
#else
success=[scanner scanDouble:&floatval];
#endif
if(!success)
{
[errors addObject:[NSString stringWithFormat:@"The option -%@ requires a "
@"floating-point number value.",option]];
return;
}
[dict setObject:[NSNumber numberWithDouble:floatval] forKey:NumberValueKey];
}
else if(type==SwitchOptionType)
{
[dict setObject:[NSNumber numberWithBool:YES] forKey:NumberValueKey];
}
}
-(void)_setDefaultValues
{
NSEnumerator *enumerator=[options objectEnumerator];
NSMutableDictionary *dict;
while((dict=[enumerator nextObject]))
{
id defaultvalue=[dict objectForKey:DefaultValueKey];
if(!defaultvalue) continue;
NSString *type=[dict objectForKey:OptionTypeKey];
if(type==StringOptionType)
{
if(![dict objectForKey:StringValueKey]) [dict setObject:defaultvalue forKey:StringValueKey];
}
else if(type==MultipleChoiceOptionType)
{
if(![dict objectForKey:NumberValueKey])
{
int index=[defaultvalue unsignedIntValue];
NSArray *allowedvalues=[dict objectForKey:AllowedValuesKey];
[dict setObject:[allowedvalues objectAtIndex:index] forKey:StringValueKey];
[dict setObject:defaultvalue forKey:NumberValueKey];
}
}
else if(type==IntegerOptionType||type==FloatingPointOptionType)
{
if(![dict objectForKey:NumberValueKey]) [dict setObject:defaultvalue forKey:NumberValueKey];
}
}
}
-(void)_parseRemainingArguments:(NSArray *)remainingarguments errors:(NSMutableArray *)errors
{
[remainingargumentarray autorelease];
remainingargumentarray=[remainingarguments retain];
}
-(void)_enforceRequirementsWithErrors:(NSMutableArray *)errors
{
if([alwaysrequiredoptions count]) [self _requireOptionsInArray:alwaysrequiredoptions when:@"" errors:errors];
NSEnumerator *enumerator=[options objectEnumerator];
NSDictionary *dict;
while((dict=[enumerator nextObject]))
{
NSArray *names=[dict objectForKey:NamesKey];
NSString *name=[names objectAtIndex:0];
NSArray *requiredoptions=[dict objectForKey:RequiredOptionsKey];
if(requiredoptions)
if([self _isOptionDefined:name])
{
[self _requireOptionsInArray:requiredoptions
when:[NSString stringWithFormat:@" when the option %@ is used",[self _describeOption:name]]
errors:errors];
}
}
}
-(void)_requireOptionsInArray:(NSArray *)requiredoptions when:(NSString *)when errors:(NSMutableArray *)errors
{
NSMutableSet *set=[NSMutableSet set];
NSEnumerator *enumerator=[requiredoptions objectEnumerator];
NSString *requiredoption;
while((requiredoption=[enumerator nextObject]))
{
if(![self _isOptionDefined:requiredoption]) [set addObject:requiredoption];
}
if([set count]==0) return;
NSMutableArray *array=[NSMutableArray array];
enumerator=[optionordering objectEnumerator];
NSString *option;
while((option=[enumerator nextObject]))
{
if([set containsObject:option]) [array addObject:[self _describeOption:option]];
}
if([array count]==1)
{
[errors addObject:[NSString stringWithFormat:@"The option %@ is required%@.",[array objectAtIndex:0],when]];
}
else
{
[errors addObject:[NSString stringWithFormat:@"The options %@ and %@ are required%@.",[array objectAtIndex:0],
[[array subarrayWithRange:NSMakeRange(0,[array count]-1)] componentsJoinedByString:@", "],when]];
}
}
-(BOOL)_isOptionDefined:(NSString *)option
{
NSDictionary *dict=[options objectForKey:option];
return [dict objectForKey:StringValueKey]||[dict objectForKey:NumberValueKey]||[dict objectForKey:ArrayValueKey];
}
-(NSString *)_describeOption:(NSString *)name
{
NSDictionary *dict=[options objectForKey:name];
NSArray *names=[dict objectForKey:NamesKey];
if([names count]==1) return [names objectAtIndex:0];
else return [NSString stringWithFormat:@"-%@ (-%@)",[names objectAtIndex:0],
[[names subarrayWithRange:NSMakeRange(1,[names count]-1)] componentsJoinedByString:@", -"]];
}
-(NSString *)_describeOptionAndArgument:(NSString *)name
{
NSDictionary *dict=[options objectForKey:name];
NSString *argdescription=[dict objectForKey:ArgumentDescriptionKey];
if(argdescription) return [NSString stringWithFormat:@"%@ <%@>",[self _describeOption:name],argdescription];
else return [self _describeOption:name];
}
-(void)_reportErrors:(NSArray *)errors
{
NSEnumerator *enumerator=[errors objectEnumerator];
NSString *error;
while((error=[enumerator nextObject]))
{
[error print];
[@"\n" print];
}
}
-(void)printUsage
{
[usageheader print];
int terminalwidth=[NSString terminalWidth];
int count=[optionordering count];
int maxlength=0;
NSMutableArray *optiondescriptions=[NSMutableArray array];
for(int i=0;i<count;i++)
{
NSString *option=[optionordering objectAtIndex:i];
NSString *description=[self _describeOptionAndArgument:option];
[optiondescriptions addObject:description];
int length=[description length];
if(length>maxlength) maxlength=length;
}
int columnwidth1=maxlength+2;
int columnwidth2=terminalwidth-columnwidth1;
for(int i=0;i<count;i++)
{
NSString *option=[optionordering objectAtIndex:i];
NSString *optiondescription=[optiondescriptions objectAtIndex:i];
NSDictionary *dict=[options objectForKey:option];
[optiondescription print];
for(int i=[optiondescription length];i<columnwidth1;i++)
[@" " print];
NSArray *lines=[[dict objectForKey:DescriptionKey] linesWrappedToWidth:columnwidth2];
int numlines=[lines count];
for(int i=0;i<numlines;i++)
{
if(i!=0) for(int j=0;j<columnwidth1;j++) [@" " print];
[[lines objectAtIndex:i] print];
[@"\n" print];
}
}
[usagefooter print];
}
-(NSString *)stringValueForOption:(NSString *)option
{
return [[options objectForKey:option] objectForKey:StringValueKey];
}
-(NSArray *)stringArrayValueForOption:(NSString *)option
{
return [[options objectForKey:option] objectForKey:ArrayValueKey];
}
-(int)intValueForOption:(NSString *)option
{
return [[[options objectForKey:option] objectForKey:NumberValueKey] intValue];
}
-(float)floatValueForOption:(NSString *)option
{
return [[[options objectForKey:option] objectForKey:NumberValueKey] floatValue];
}
-(double)doubleValueForOption:(NSString *)option
{
return [[[options objectForKey:option] objectForKey:NumberValueKey] doubleValue];
}
-(BOOL)boolValueForOption:(NSString *)option
{
return [[[options objectForKey:option] objectForKey:NumberValueKey] boolValue];
}
-(NSArray *)remainingArguments
{
return remainingargumentarray;
}
-(void)_assertOptionNameIsUnique:(NSString *)option
{
if([options objectForKey:option])
[NSException raise:NSInvalidArgumentException format:@"Attempted to add duplicate option \"%@\".",option];
}
-(void)_raiseUnknownOption:(NSString *)option
{
[NSException raise:NSInvalidArgumentException format:@"Unknown option \"%@\".",option];
}
@end