├── .gitignore ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── BuildHeaders │ └── GBCli │ │ ├── GBCli.h │ │ ├── GBCommandLineParser.h │ │ ├── GBOptionsHelper.h │ │ ├── GBPrint.h │ │ └── GBSettings.h ├── GBCli │ ├── GBCli │ │ └── src │ │ │ ├── GBCli.h │ │ │ ├── GBCommandLineParser.h │ │ │ ├── GBCommandLineParser.m │ │ │ ├── GBOptionsHelper.h │ │ │ ├── GBOptionsHelper.m │ │ │ ├── GBPrint.h │ │ │ ├── GBPrint.m │ │ │ ├── GBSettings.h │ │ │ └── GBSettings.m │ ├── LICENSE │ └── Readme.markdown ├── Headers │ └── GBCli │ │ ├── GBCli.h │ │ ├── GBCommandLineParser.h │ │ ├── GBOptionsHelper.h │ │ ├── GBPrint.h │ │ └── GBSettings.h ├── Local Podspecs │ └── GBCli.podspec ├── Manifest.lock ├── Pods-GBCli-Private.xcconfig ├── Pods-GBCli-dummy.m ├── Pods-GBCli-prefix.pch ├── Pods-GBCli.xcconfig ├── Pods-acknowledgements.markdown ├── Pods-acknowledgements.plist ├── Pods-dummy.m ├── Pods-environment.h ├── Pods-resources.sh ├── Pods.xcconfig └── Pods.xcodeproj │ └── project.pbxproj ├── Readme.md ├── symbolicator.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── symbolicator.xcworkspace └── contents.xcworkspacedata └── symbolicator ├── ArchiveHandler.swift ├── FileSymbolicator.swift ├── ObjCRegex ├── RegExCategories.h └── RegExCategories.m ├── Options.swift ├── Settings.swift ├── Symbolicator.swift ├── main.swift └── symbolicator-Bridging-Header.h /.gitignore: -------------------------------------------------------------------------------- 1 | *-AutoGenerated!.* 2 | 3 | # Xcode 4 | xcuserdata/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 by Tomaz Kragelj 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, "10.9" 2 | 3 | pod "GBCli", :git => "../GBCli" 4 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - GBCli (1.1) 3 | 4 | DEPENDENCIES: 5 | - GBCli (from `../GBCli`) 6 | 7 | EXTERNAL SOURCES: 8 | GBCli: 9 | :git: ../GBCli 10 | 11 | SPEC CHECKSUMS: 12 | GBCli: 3527037ed1a797dbcc7ea32a86287abae0eb614f 13 | 14 | COCOAPODS: 0.33.1 15 | -------------------------------------------------------------------------------- /Pods/BuildHeaders/GBCli/GBCli.h: -------------------------------------------------------------------------------- 1 | ../../GBCli/GBCli/src/GBCli.h -------------------------------------------------------------------------------- /Pods/BuildHeaders/GBCli/GBCommandLineParser.h: -------------------------------------------------------------------------------- 1 | ../../GBCli/GBCli/src/GBCommandLineParser.h -------------------------------------------------------------------------------- /Pods/BuildHeaders/GBCli/GBOptionsHelper.h: -------------------------------------------------------------------------------- 1 | ../../GBCli/GBCli/src/GBOptionsHelper.h -------------------------------------------------------------------------------- /Pods/BuildHeaders/GBCli/GBPrint.h: -------------------------------------------------------------------------------- 1 | ../../GBCli/GBCli/src/GBPrint.h -------------------------------------------------------------------------------- /Pods/BuildHeaders/GBCli/GBSettings.h: -------------------------------------------------------------------------------- 1 | ../../GBCli/GBCli/src/GBSettings.h -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBCli.h: -------------------------------------------------------------------------------- 1 | // 2 | // GBCli.h 3 | // GBCli 4 | // 5 | // Created by Tomaz Kragelj on 23.05.14. 6 | // 7 | // 8 | 9 | // Imports all source files for GBCli 10 | 11 | #import "GBCommandLineParser.h" 12 | #import "GBSettings.h" 13 | #import "GBOptionsHelper.h" 14 | #import "GBPrint.h" 15 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBCommandLineParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // GBCommandLineParser.h 3 | // GBCli 4 | // 5 | // Created by Tomaž Kragelj on 3/12/12. 6 | // Copyright (c) 2012 Tomaz Kragelj. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class GBSettings; 12 | 13 | typedef NSUInteger GBValueRequirements; 14 | typedef NSUInteger GBParseFlags; 15 | typedef void(^GBCommandLineParseBlock)(GBParseFlags flags, NSString *argument, id value, BOOL *stop); 16 | 17 | /** Handles command line arguments parsing. 18 | 19 | To use the class, instantiate it, register all options, ask it to parse command line arguments and finally use accessors to read the data. Here's one possible way: 20 | 21 | ``` 22 | int main(int argv, char **argv) { 23 | GBCommandLineParser *parser = [[GBCommandLineParser alloc] init]; 24 | [parser registerOption:@"verbose" shortcut:'v' requirement:GBValueRequired]; 25 | [parser registerSwitch:@"help" shortcut:'h']; 26 | ... 27 | [parser parseOptionsWithArguments:argv count:argc block:^(NSString *argument, id value, BOOL *stop) { 28 | if (value == GBCommandLineArgumentResults.unknownArgument) { 29 | *stop = YES; 30 | return; 31 | } else if (value == GBCommandLineArgumentResults.missingValue) { 32 | *stop = YES; 33 | return; 34 | } 35 | ... you can do somethig with valid argument here if needed 36 | }]; 37 | ... you can access all parsed options and arguments here... 38 | id value1 = [parser valueForOption:@"verbose"]; 39 | NSArray *arguments = parser.arguments; 40 | return 0; 41 | } 42 | ``` 43 | 44 | @warning **Important:** This class is similar to `DDCli` from Dave Dribin, but works under arc! It also uses a different approach to command line parsing - instead of using "push" model like `DDCli` (i.e. sending KVO notifications to pass arguments to a delegate), it uses "pull" model: you let it parse the values and then ask the class for specific argument values. With this approach, it centralizes arguments handling - instead of splitting it over various delegate and KVO mutator methods, you can do it in a single place. 45 | */ 46 | @interface GBCommandLineParser : NSObject 47 | 48 | #pragma mark - Options registration 49 | 50 | - (void)beginRegisterOptionGroup:(NSString *)name; 51 | - (void)endRegisterOptionGroup; // optional; if another beginRegisterOptionGroup: is enountered, a new group is started. Use it if you want to register "standalone" options after group. 52 | - (void)registerOption:(NSString *)longOption shortcut:(char)shortOption requirement:(GBValueRequirements)requirement; 53 | - (void)registerOption:(NSString *)longOption requirement:(GBValueRequirements)requirement; 54 | - (void)registerSwitch:(NSString *)longOption shortcut:(char)shortOption; 55 | - (void)registerSwitch:(NSString *)longOption; 56 | 57 | #pragma mark - Options parsing 58 | 59 | - (void)registerSettings:(GBSettings *)settings; 60 | - (BOOL)parseOptionsUsingDefaultArguments; 61 | - (BOOL)parseOptionsWithArguments:(char **)argv count:(int)argc; 62 | - (BOOL)parseOptionsWithArguments:(NSArray *)arguments commandLine:(NSString *)cmd; 63 | 64 | - (BOOL)parseOptionsUsingDefaultArgumentsWithBlock:(GBCommandLineParseBlock)handler; 65 | - (BOOL)parseOptionsWithArguments:(char **)argv count:(int)argc block:(GBCommandLineParseBlock)handler; 66 | - (BOOL)parseOptionsWithArguments:(NSArray *)arguments commandLine:(NSString *)cmd block:(GBCommandLineParseBlock)handler; 67 | 68 | #pragma mark - Getting parsed results 69 | 70 | - (id)valueForOption:(NSString *)longOption; 71 | 72 | @property (nonatomic, readonly) NSArray *arguments; 73 | 74 | @end 75 | 76 | #pragma mark - 77 | 78 | /** Various command line argument value requirements. */ 79 | typedef NS_ENUM(NSUInteger, GBValueFlags) { 80 | GBValueRequired, ///< Command line argument requires a value. 81 | GBValueOptional, ///< Command line argument can optionally have a value, but is not required. 82 | GBValueNone ///< Command line argument is on/off switch. 83 | }; 84 | 85 | /** Various parsing flags. */ 86 | typedef NS_ENUM(NSUInteger, GBParseFlag) { 87 | GBParseFlagOption, 88 | GBParseFlagArgument, 89 | GBParseFlagWrongGroup, 90 | GBParseFlagMissingValue, 91 | GBParseFlagUnknownOption, 92 | }; 93 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBCommandLineParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // GBCommandLineParser.m 3 | // GBCli 4 | // 5 | // Created by Tomaž Kragelj on 3/12/12. 6 | // Copyright (c) 2012 Tomaz Kragelj. All rights reserved. 7 | // 8 | 9 | #import "GBPrint.h" 10 | #import "GBSettings.h" 11 | #import "GBCommandLineParser.h" 12 | 13 | static NSString * const GBCommandLineLongOptionKey = @"long"; 14 | static NSString * const GBCommandLineShortOptionKey = @"short"; 15 | static NSString * const GBCommandLineRequirementKey = @"requirement"; 16 | static NSString * const GBCommandLineOptionGroupKey = @"group"; // this is returned while parsing to indicate an option group was detected. 17 | static NSString * const GBCommandLineNotAnOptionKey = @"not-an-option"; // this is returned while parsing to indicate an argument was detected. 18 | 19 | #pragma mark - 20 | 21 | @interface GBCommandLineParser () 22 | - (NSDictionary *)optionDataForOption:(NSString *)shortOrLongName value:(NSString **)value; 23 | - (BOOL)isShortOrLongOptionName:(NSString *)value; 24 | @property (nonatomic, strong) GBSettings *settings; // optional (only required by simplified parsing methods) 25 | @property (nonatomic, strong) NSMutableDictionary *parsedOptions; 26 | @property (nonatomic, strong) NSMutableArray *parsedArguments; 27 | @property (nonatomic, strong) NSMutableDictionary *registeredOptionsByLongNames; 28 | @property (nonatomic, strong) NSMutableDictionary *registeredOptionsByShortNames; 29 | @property (nonatomic, strong) NSMutableDictionary *registeredOptionGroupsByNames; 30 | @property (nonatomic, strong) NSMutableSet *currentOptionsGroupOptions; // this is used both while registering and while parsing arguments 31 | @property (nonatomic, copy) NSString *currentOptionsGroupName; // used while parsing 32 | @end 33 | 34 | #pragma mark - 35 | 36 | @implementation GBCommandLineParser 37 | 38 | @synthesize parsedOptions; 39 | @synthesize parsedArguments; 40 | @synthesize registeredOptionsByLongNames; 41 | @synthesize registeredOptionsByShortNames; 42 | 43 | #pragma mark - Initialization & disposal 44 | 45 | - (instancetype)init { 46 | self = [super init]; 47 | if (self) { 48 | self.registeredOptionsByLongNames = [NSMutableDictionary dictionary]; 49 | self.registeredOptionsByShortNames = [NSMutableDictionary dictionary]; 50 | self.registeredOptionGroupsByNames = [NSMutableDictionary dictionary]; 51 | self.parsedOptions = [NSMutableDictionary dictionary]; 52 | self.parsedArguments = [NSMutableArray array]; 53 | } 54 | return self; 55 | } 56 | 57 | #pragma mark - Options registration 58 | 59 | - (void)beginRegisterOptionGroup:(NSString *)name { 60 | self.currentOptionsGroupOptions = self.registeredOptionGroupsByNames[name]; 61 | 62 | // Warn if we already have the given group. 63 | if (self.registeredOptionGroupsByNames[name]) { 64 | fprintf(stderr, "Group %s is already registered!", [name UTF8String]); 65 | return; 66 | } 67 | 68 | // Create options group data into which we'll be registering options from now on. 69 | self.currentOptionsGroupOptions = [NSMutableSet set]; 70 | self.registeredOptionGroupsByNames[name] = self.currentOptionsGroupOptions; 71 | } 72 | 73 | - (void)endRegisterOptionGroup { 74 | self.currentOptionsGroupName = nil; 75 | self.currentOptionsGroupOptions = nil; 76 | } 77 | 78 | - (void)registerOption:(NSString *)longOption shortcut:(char)shortOption requirement:(GBValueRequirements)requirement { 79 | // Register option data. 80 | NSMutableDictionary *data = [NSMutableDictionary dictionary]; 81 | data[GBCommandLineLongOptionKey] = longOption; 82 | data[GBCommandLineRequirementKey] = @(requirement); 83 | self.registeredOptionsByLongNames[longOption] = data; 84 | [self.currentOptionsGroupOptions addObject:longOption]; 85 | 86 | // Register short option data if needed. 87 | if (shortOption > 0) { 88 | NSString *shortOptionKey = [NSString stringWithFormat:@"%c", shortOption]; 89 | data[GBCommandLineShortOptionKey] = @(shortOption); 90 | self.registeredOptionsByShortNames[shortOptionKey] = data; 91 | } 92 | 93 | // If this is a swich, register negative variant (i.e. if the option is named --option, negative form is --no-option). Note that negative variant doesn't support short code! 94 | if (requirement == GBValueNone) { 95 | NSMutableDictionary *negativeVariantData = [NSMutableDictionary dictionary]; 96 | NSString *negativeVariantLongOption = [NSString stringWithFormat:@"no-%@", longOption]; 97 | negativeVariantData[GBCommandLineLongOptionKey] = negativeVariantLongOption; 98 | negativeVariantData[GBCommandLineRequirementKey] = @(requirement); 99 | self.registeredOptionsByLongNames[negativeVariantLongOption] = negativeVariantData; 100 | [self.currentOptionsGroupOptions addObject:negativeVariantData]; 101 | } 102 | } 103 | 104 | - (void)registerOption:(NSString *)longOption requirement:(GBValueRequirements)requirement { 105 | [self registerOption:longOption shortcut:0 requirement:requirement]; 106 | } 107 | 108 | - (void)registerSwitch:(NSString *)longOption shortcut:(char)shortOption { 109 | [self registerOption:longOption shortcut:shortOption requirement:GBValueNone]; 110 | } 111 | 112 | - (void)registerSwitch:(NSString *)longOption { 113 | [self registerSwitch:longOption shortcut:0]; 114 | } 115 | 116 | #pragma mark - Options parsing - Simple methods with default behavior 117 | 118 | - (void)registerSettings:(GBSettings *)settings { 119 | self.settings = settings; 120 | } 121 | 122 | - (BOOL)parseOptionsUsingDefaultArguments { 123 | [self validateSimplifiedOptionsWithSelector:_cmd]; 124 | return [self parseOptionsUsingDefaultArgumentsWithBlock:[self simplifiedOptionsParserBlock]]; 125 | } 126 | 127 | - (BOOL)parseOptionsWithArguments:(char **)argv count:(int)argc { 128 | [self validateSimplifiedOptionsWithSelector:_cmd]; 129 | return [self parseOptionsWithArguments:argv count:argc block:[self simplifiedOptionsParserBlock]]; 130 | } 131 | 132 | - (BOOL)parseOptionsWithArguments:(NSArray *)arguments commandLine:(NSString *)cmd { 133 | [self validateSimplifiedOptionsWithSelector:_cmd]; 134 | return [self parseOptionsWithArguments:arguments commandLine:cmd block:[self simplifiedOptionsParserBlock]]; 135 | } 136 | 137 | - (GBCommandLineParseBlock)simplifiedOptionsParserBlock { 138 | return ^(GBParseFlags flags, NSString *argument, id value, BOOL *stop) { 139 | switch (flags) { 140 | case GBParseFlagUnknownOption: 141 | gbfprintln(stderr, @"Unknown command line option %@, try --help!", argument); 142 | break; 143 | case GBParseFlagMissingValue: 144 | gbfprintln(stderr, @"Missing value for command line option %s, try --help!", argument); 145 | break; 146 | case GBParseFlagWrongGroup: 147 | gbfprintln(stderr, @"Invalid option %@ for group %@!", argument, self.currentOptionsGroupName); 148 | break; 149 | case GBParseFlagArgument: 150 | [self.settings addArgument:value]; 151 | break; 152 | case GBParseFlagOption: 153 | [self.settings setObject:value forKey:argument]; 154 | break; 155 | } 156 | }; 157 | } 158 | 159 | - (void)validateSimplifiedOptionsWithSelector:(SEL)sel { 160 | NSAssert(self.settings != nil, @"%@ requires you to supply GBSettings instance via registerSettings: method!", NSStringFromSelector(sel)); 161 | } 162 | 163 | #pragma mark - Options parsing - Methods with customizations 164 | 165 | - (BOOL)parseOptionsUsingDefaultArgumentsWithBlock:(GBCommandLineParseBlock)handler { 166 | NSProcessInfo *processInfo = [NSProcessInfo processInfo]; 167 | NSString *command = [processInfo processName]; 168 | NSMutableArray *arguments = [[processInfo arguments] mutableCopy]; 169 | [arguments removeObjectAtIndex:0]; 170 | return [self parseOptionsWithArguments:arguments commandLine:command block:handler]; 171 | } 172 | 173 | - (BOOL)parseOptionsWithArguments:(char **)argv count:(int)argc block:(GBCommandLineParseBlock)handler { 174 | if (argc == 0) return YES; 175 | NSString *command = [NSString stringWithUTF8String:argv[0]]; 176 | NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:argc - 1]; 177 | for (int i=1; i 10 | #import "GBCommandLineParser.h" 11 | 12 | @class GBCommandLineParser; 13 | @class GBSettings; 14 | 15 | /** Various option flags. You can also use GBValueRequirement values here! */ 16 | typedef NS_OPTIONS(NSUInteger, GBOptionFlags) { 17 | GBOptionRequiredValue = 0, ///< Command line argument requires a value. 18 | GBOptionOptionalValue = 1 << 0, ///< Command line argument can optionally have a value, but is not required. 19 | GBOptionNoValue = 1 << 1,///< Command line argument is on/off switch. 20 | GBOptionSeparator = 1 << 3, ///< Option is separator, not real option definition. 21 | GBOptionGroup = 1 << 4, ///< Option is an option gorup, not actual option definition. 22 | GBOptionNoCmdLine = 1 << 5, ///< Option is not used on command line, don't register to parser. 23 | GBOptionNoPrint = 1 << 6, ///< Option should be excluded from print settings display. 24 | GBOptionNoHelp = 1 << 7, ///< Option should be excluded from help display. 25 | GBOptionInvisible = GBOptionNoPrint | GBOptionNoHelp, 26 | }; 27 | 28 | /** Description of a single option or separator. */ 29 | typedef struct { 30 | char shortOption; ///< Short option char or `0` if not used. 31 | __unsafe_unretained NSString *longOption; ///< Long option name - required for options. 32 | __unsafe_unretained NSString *description; ///< Description of the option. 33 | GBOptionFlags flags; ///< Various flags. 34 | } GBOptionDefinition; 35 | 36 | /** Block used to fetch strings from user code. */ 37 | typedef NSString *(^GBOptionStringBlock)(void); 38 | 39 | #pragma mark - 40 | 41 | /** Helper class for nicer integration between GBSettings and GBCommandLineParser. 42 | 43 | Although using this class is optional, it provides several nice features and automations out of the box (although you can subclass if your want to customize): 44 | 45 | - Registration of options to GBCommandLineParser. 46 | - Print version information (subclass to customize). 47 | - Print help (subclass to customize). 48 | - Print values, preserving their GBSettings level hierarchy (subclass to customize). 49 | 50 | One example of usage: 51 | 52 | ``` 53 | int main(int argc, char **argv) { 54 | GBSettings *factory = [GBSettings settingsWithName:@"Factory" parent:nil]; 55 | GBSettings *settings = [GBSettings settingsWithName@"CmdLine" parent:factory]; 56 | 57 | OptionsHelper *options = [[OptionsHelper alloc] init]; 58 | [options registerSeparator:@"PATHS"]; 59 | [options registerOption:'i' long:@"input" description:@"Input path" flags:GBValueRequired]; 60 | [options registerOption:'o' long:@"output" description:@"Output path" flags:GBValueRequired]; 61 | [options registerSeparator:@"MISCELLANEOUS"]; 62 | [options registerOption:0 long:@"version" description:@"Display version and exit" flags:GBValueNone|GBOptionNoPrint]; 63 | [options registerOption:'?' long:@"help" description:@"Display this help and exit" flags:GBValueNone|GBOptionNoPrint]; 64 | 65 | GBCommandLineParser *parser = [[GBCommandLineParser alloc] init]; 66 | [options registerOptionsToCommandLineParser:parser]; 67 | __block BOOL commandLineValid = YES; 68 | __block BOOL finished = NO; 69 | [parser parseOptionsWithArguments:argv count:argc block:^(NSString *argument, id value, BOOL *stop) { 70 | if (value == GBCommandLineArgumentResults.unknownArgument) { 71 | // unknown argument 72 | commandLineValid = NO; 73 | *stop = YES; 74 | } else if (value == GBCommandLineArgumentResults.missingValue) { 75 | // known argument but missing value 76 | commandLineValid = NO; 77 | *stop = YES; 78 | } else if ([argument isEqualToString:@"version"]) { 79 | [options printVersion]; 80 | finished = YES; 81 | *stop = YES; 82 | } else if ([argument isEqualToString:@"help"]) { 83 | [options printHelp]; 84 | finished = YES; 85 | *stop = YES; 86 | } else { 87 | [settings setObject:value forKey:argument]; 88 | } 89 | }]; 90 | 91 | if (finished) return 0; 92 | if (!commandLineValue) return 1; 93 | 94 | [options printValuesFromSettings:settings]; 95 | return 0; 96 | } 97 | ``` 98 | 99 | There are several hooks by which you can inject text into default output. The hooks use block API, for example printValuesHeader, printHelpHeader etc. An example: 100 | 101 | ``` 102 | int main(int argc, char **argv) { 103 | ... 104 | GBOptionsHelper *options = [[OptionsHelper alloc] init]; 105 | options.printHelpHeader = ^{ return @"Usage: MyTool [OPTIONS] "; }; 106 | options.printHelpFooter = ^{ return @"Thanks to everyone for their help..."; }; 107 | ... 108 | } 109 | ``` 110 | 111 | These blocks are automatically invoked when and if necessary. The strings you return from them can contain several placeholders: 112 | 113 | - `%APPNAME` is replaced by the application name, either the value returned from applicationName, or auto-generated by GBOptionsHelper itself. 114 | - `%APPVERSION` is replaced by the application version, if given via applicationVersion block or empty string otherwise. 115 | - `%APPBUILD` is replaced by the application build number, if given via applicationBuild block or empty strings otherwise. 116 | 117 | @warning **Note:** Only values from blocks related to printing text are checked for placeholders, applicationName, applicationVersion and applicationBuild aren't! 118 | */ 119 | @interface GBOptionsHelper : NSObject 120 | 121 | #pragma mark - Options registration 122 | 123 | - (void)registerOptionsFromDefinitions:(GBOptionDefinition *)definitions; // this mode doesn't support option groups at this moment! 124 | - (void)registerSeparator:(NSString *)description; 125 | - (void)registerGroup:(NSString *)name description:(NSString *)description optionsBlock:(void(^)(GBOptionsHelper *options))block; 126 | - (void)registerGroup:(NSString *)name description:(NSString *)description flags:(GBOptionFlags)flags optionsBlock:(void(^)(GBOptionsHelper *options))block; 127 | - (void)registerOption:(char)shortName long:(NSString *)longName description:(NSString *)description flags:(GBOptionFlags)flags; 128 | 129 | #pragma mark - Integration with other components 130 | 131 | - (void)registerOptionsToCommandLineParser:(GBCommandLineParser *)parser; 132 | 133 | #pragma mark - Diagnostic info 134 | 135 | - (void)printValuesFromSettings:(GBSettings *)settings; 136 | - (void)printVersion; 137 | - (void)printHelp; 138 | 139 | #pragma mark - Getting information from user 140 | 141 | @property (nonatomic, copy) GBOptionStringBlock applicationName; 142 | @property (nonatomic, copy) GBOptionStringBlock applicationVersion; 143 | @property (nonatomic, copy) GBOptionStringBlock applicationBuild; 144 | 145 | #pragma mark - Hooks for injecting text to output 146 | 147 | @property (nonatomic, copy) GBOptionStringBlock printValuesHeader; 148 | @property (nonatomic, copy) GBOptionStringBlock printValuesArgumentsHeader; 149 | @property (nonatomic, copy) GBOptionStringBlock printValuesOptionsHeader; 150 | @property (nonatomic, copy) GBOptionStringBlock printValuesFooter; 151 | 152 | @property (nonatomic, copy) GBOptionStringBlock printHelpHeader; 153 | @property (nonatomic, copy) GBOptionStringBlock printHelpFooter; 154 | 155 | @end 156 | 157 | #pragma mark - 158 | 159 | @interface GBCommandLineParser (GBOptionsHelper) 160 | - (void)registerOptions:(GBOptionsHelper *)options; 161 | @end 162 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBOptionsHelper.m: -------------------------------------------------------------------------------- 1 | // 2 | // GBOptionsHelper.m 3 | // GBCli 4 | // 5 | // Created by Tomaž Kragelj on 3/15/12. 6 | // Copyright (c) 2012 Tomaz Kragelj. All rights reserved. 7 | // 8 | 9 | #import "GBSettings.h" 10 | #import "GBOptionsHelper.h" 11 | 12 | static NSUInteger GBOptionInternalEndGroup = 1 << 10; 13 | 14 | #pragma mark - 15 | 16 | @interface OptionDefinition : NSObject 17 | @property (nonatomic, assign) char shortOption; 18 | @property (nonatomic, copy) NSString *longOption; 19 | @property (nonatomic, copy) NSString *description; 20 | @property (nonatomic, assign) GBOptionFlags flags; 21 | @end 22 | 23 | @implementation OptionDefinition 24 | @synthesize description = _description; 25 | @end 26 | 27 | #pragma mark - 28 | 29 | @interface GBOptionsHelper () 30 | @property (nonatomic, strong) NSMutableArray *registeredOptions; 31 | @end 32 | 33 | #pragma mark - 34 | 35 | @implementation GBOptionsHelper 36 | 37 | #pragma mark - Initialization & disposal 38 | 39 | - (instancetype)init { 40 | self = [super init]; 41 | if (self) { 42 | self.registeredOptions = [NSMutableArray array]; 43 | } 44 | return self; 45 | } 46 | 47 | #pragma mark - Options registration 48 | 49 | - (void)registerOptionsFromDefinitions:(GBOptionDefinition *)definitions { 50 | GBOptionDefinition *definition = definitions; 51 | while (definition->longOption || definition->description) { 52 | [self registerOption:definition->shortOption long:definition->longOption description:definition->description flags:definition->flags]; 53 | definition++; 54 | } 55 | } 56 | 57 | - (void)registerSeparator:(NSString *)description { 58 | [self registerOption:0 long:nil description:description flags:GBOptionSeparator]; 59 | } 60 | 61 | - (void)registerGroup:(NSString *)name description:(NSString *)description optionsBlock:(void(^)(GBOptionsHelper *options))block { 62 | [self registerGroup:name description:description flags:0 optionsBlock:block]; 63 | } 64 | 65 | - (void)registerGroup:(NSString *)name description:(NSString *)description flags:(GBOptionFlags)flags optionsBlock:(void(^)(GBOptionsHelper *options))block { 66 | NSParameterAssert(block != nil); 67 | OptionDefinition *definition = [[OptionDefinition alloc] init]; 68 | definition.shortOption = 0; 69 | definition.longOption = name; 70 | definition.description = description; 71 | definition.flags = GBOptionGroup | flags; 72 | [self.registeredOptions addObject:definition]; 73 | 74 | block(self); 75 | 76 | OptionDefinition *endDefinition = [[OptionDefinition alloc] init]; 77 | endDefinition.flags = GBOptionInternalEndGroup; 78 | [self.registeredOptions addObject:endDefinition]; 79 | } 80 | 81 | - (void)registerOption:(char)shortName long:(NSString *)longName description:(NSString *)description flags:(GBOptionFlags)flags { 82 | OptionDefinition *definition = [[OptionDefinition alloc] init]; 83 | definition.shortOption = shortName; 84 | definition.longOption = longName; 85 | definition.description = description; 86 | definition.flags = flags; 87 | [self.registeredOptions addObject:definition]; 88 | } 89 | 90 | #pragma mark - Integration with other components 91 | 92 | - (void)registerOptionsToCommandLineParser:(GBCommandLineParser *)parser { 93 | [self enumerateOptions:^(OptionDefinition *definition, BOOL *stop) { 94 | if (![self isCmdLine:definition]) return; 95 | if ([self isSeparator:definition]) return; 96 | 97 | if ([self isOptionGroup:definition]) { 98 | [parser beginRegisterOptionGroup:definition.longOption]; 99 | return; 100 | } 101 | 102 | if ([self isOptionGroupEnd:definition]) { 103 | [parser endRegisterOptionGroup]; 104 | return; 105 | } 106 | 107 | NSUInteger requirements = [self requirements:definition]; 108 | [parser registerOption:definition.longOption shortcut:definition.shortOption requirement:requirements]; 109 | }]; 110 | } 111 | 112 | #pragma mark - Diagnostic info 113 | 114 | - (void)printValuesFromSettings:(GBSettings *)settings { 115 | #define GB_UPDATE_MAX_LENGTH(value) \ 116 | NSNumber *length = [lengths objectAtIndex:columns.count]; \ 117 | NSUInteger maxLength = MAX(value.length, length.unsignedIntegerValue); \ 118 | if (maxLength > length.unsignedIntegerValue) { \ 119 | NSNumber *newMaxLength = @(maxLength); \ 120 | [lengths replaceObjectAtIndex:columns.count withObject:newMaxLength]; \ 121 | } 122 | NSMutableArray *rows = [NSMutableArray array]; 123 | NSMutableArray *lengths = [NSMutableArray array]; 124 | __weak GBOptionsHelper *blockSelf = self; 125 | __block NSUInteger settingsHierarchyLevels = 0; 126 | 127 | // First add header row. Note that first element is the setting. 128 | NSMutableArray *headers = [NSMutableArray arrayWithObject:@"Option"]; 129 | [lengths addObject:@([headers.lastObject length])]; 130 | [settings enumerateSettings:^(GBSettings *settings, BOOL *stop) { 131 | [headers addObject:settings.name]; 132 | [lengths addObject:@(settings.name.length)]; 133 | settingsHierarchyLevels++; 134 | }]; 135 | [rows addObject:headers]; 136 | 137 | // Append all rows for options. 138 | __block NSUInteger lastSeparatorIndex = 0; 139 | [self enumerateOptions:^(OptionDefinition *definition, BOOL *stop) { 140 | if (![blockSelf isPrint:definition]) return; 141 | if ([self isOptionGroupEnd:definition]) return; 142 | 143 | // Add separator. Note that we don't care about its length, we'll simply draw it over the whole line if needed. 144 | if ([blockSelf isSeparator:definition]) { 145 | if (rows.count == lastSeparatorIndex) { 146 | [rows removeLastObject]; 147 | [rows removeLastObject]; 148 | } 149 | [rows addObject:@[]]; 150 | [rows addObject:@[ definition.description ] ]; 151 | lastSeparatorIndex = rows.count; 152 | return; 153 | } 154 | 155 | // Add group. 156 | if ([blockSelf isOptionGroup:definition]) { 157 | NSMutableString *description = [definition.longOption mutableCopy]; 158 | if ([definition.description length] > 0) [description appendFormat:@" %@", definition.description]; 159 | [rows addObject:@[]]; 160 | [rows addObject:@[ description ]]; 161 | return; 162 | } 163 | 164 | NSMutableArray *columns = [NSMutableArray array]; 165 | NSString *longOption = definition.longOption; 166 | GB_UPDATE_MAX_LENGTH(longOption) 167 | [columns addObject:longOption]; 168 | 169 | // Now append value for the option on each settings level and update maximum size. 170 | [settings enumerateSettings:^(GBSettings *settings, BOOL *stop) { 171 | NSString *columnData = @""; 172 | if ([settings isKeyPresentAtThisLevel:longOption]) { 173 | id value = [settings objectForKey:longOption]; 174 | if ([settings isKeyArray:longOption]) { 175 | NSMutableString *arrayValue = [NSMutableString string]; 176 | [(NSArray *)value enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) { 177 | GBSettings *level = [settings settingsForArrayValue:obj key:longOption]; 178 | if (level != settings) return; 179 | if (arrayValue.length > 0) [arrayValue appendString:@", "]; 180 | [arrayValue appendString:obj]; 181 | }]; 182 | columnData = arrayValue; 183 | } else { 184 | columnData = [value description]; 185 | } 186 | } 187 | GB_UPDATE_MAX_LENGTH(columnData) 188 | [columns addObject:columnData]; 189 | }]; 190 | 191 | // Add the row. 192 | [rows addObject:columns]; 193 | }]; 194 | 195 | // Remove last separator if there were no values. 196 | if (rows.count == lastSeparatorIndex) { 197 | [rows removeLastObject]; 198 | [rows removeLastObject]; 199 | } 200 | 201 | // Render header. 202 | [self replacePlaceholdersAndPrintStringFromBlock:self.printValuesHeader]; 203 | 204 | // Render all arguments if any. 205 | if (settings.arguments.count > 0) { 206 | [self replacePlaceholdersAndPrintStringFromBlock:self.printValuesArgumentsHeader]; 207 | [settings.arguments enumerateObjectsUsingBlock:^(NSString *argument, NSUInteger idx, BOOL *stop) { 208 | printf("- %s", argument.UTF8String); 209 | if (settingsHierarchyLevels > 1) { 210 | GBSettings *level = [settings settingsForArgument:argument]; 211 | printf(" (%s)", level.name.UTF8String); 212 | } 213 | printf("\n"); 214 | }]; 215 | printf("\n"); 216 | } 217 | 218 | // Render all rows. 219 | [self replacePlaceholdersAndPrintStringFromBlock:self.printValuesOptionsHeader]; 220 | [rows enumerateObjectsUsingBlock:^(NSArray *columns, NSUInteger rowIdx, BOOL *stopRow) { 221 | NSMutableString *output = [NSMutableString string]; 222 | [columns enumerateObjectsUsingBlock:^(NSString *value, NSUInteger colIdx, BOOL *stopCol) { 223 | NSUInteger columnSize = [[lengths objectAtIndex:colIdx] unsignedIntegerValue]; 224 | NSUInteger valueSize = value.length; 225 | [output appendString:value]; 226 | while (valueSize <= columnSize) { 227 | [output appendString:@" "]; 228 | valueSize++; 229 | } 230 | }]; 231 | printf("%s\n", output.UTF8String); 232 | }]; 233 | 234 | // Render footer. 235 | [self replacePlaceholdersAndPrintStringFromBlock:self.printValuesFooter]; 236 | } 237 | 238 | - (void)printVersion { 239 | NSMutableString *output = [NSMutableString stringWithFormat:@"%@", self.applicationNameFromBlockOrDefault]; 240 | NSString *version = self.applicationVersionFromBlockOrNil; 241 | NSString *build = self.applicationBuildFromBlockOrNil; 242 | if (version) [output appendFormat:@": version %@", version]; 243 | if (build) [output appendFormat:@" (build %@)", build]; 244 | printf("%s\n", output.UTF8String); 245 | } 246 | 247 | - (void)printHelp { 248 | // Prepare all rows. 249 | __block NSUInteger maxNameTypeLength = 0; 250 | __block NSUInteger lastSeparatorIndex = NSNotFound; 251 | NSMutableArray *rows = [NSMutableArray array]; 252 | [self enumerateOptions:^(OptionDefinition *definition, BOOL *stop) { 253 | if (![self isHelp:definition]) return; 254 | if ([self isOptionGroupEnd:definition]) return; 255 | 256 | // Prepare separator. Remove previous one if there were no values prepared for it. 257 | if ([self isSeparator:definition]) { 258 | if (rows.count == lastSeparatorIndex) { 259 | [rows removeLastObject]; 260 | [rows removeLastObject]; 261 | } 262 | [rows addObject:@[]]; 263 | [rows addObject:@[ definition.description ]]; 264 | lastSeparatorIndex = rows.count; 265 | return; 266 | } 267 | 268 | // Add group. 269 | if ([self isOptionGroup:definition]) { 270 | NSMutableString *description = [definition.longOption mutableCopy]; 271 | if ([definition.description length] > 0) [description appendFormat:@" %@", definition.description]; 272 | [rows addObject:@[]]; 273 | [rows addObject:@[ description ]]; 274 | return; 275 | } 276 | 277 | // Prepare option description. 278 | NSString *shortOption = (definition.shortOption > 0) ? [NSString stringWithFormat:@"-%c", definition.shortOption] : @" "; 279 | NSString *longOption = [NSString stringWithFormat:@"--%@", definition.longOption]; 280 | NSString *description = definition.description ? definition.description : @""; 281 | NSUInteger requirements = [self requirements:definition]; 282 | 283 | // Prepare option type and update longest option+type string size for better alignment later on. 284 | NSString *type = @""; 285 | if (requirements == GBValueRequired) 286 | type = @" "; 287 | else if (requirements == GBValueOptional) 288 | type = @" []"; 289 | maxNameTypeLength = MAX(longOption.length + type.length, maxNameTypeLength); 290 | NSString *nameAndType = [NSString stringWithFormat:@"%@%@", longOption, type]; 291 | 292 | // Add option info to rows array. 293 | NSMutableArray *columns = [NSMutableArray array]; 294 | [columns addObject:shortOption]; 295 | [columns addObject:nameAndType]; 296 | [columns addObject:description]; 297 | [rows addObject:columns]; 298 | }]; 299 | 300 | // Remove last separator if there were no values. 301 | if (rows.count == lastSeparatorIndex) { 302 | [rows removeLastObject]; 303 | [rows removeLastObject]; 304 | } 305 | 306 | // Render header. 307 | [self replacePlaceholdersAndPrintStringFromBlock:self.printHelpHeader]; 308 | 309 | // Render all rows aligning long option columns properly. 310 | [rows enumerateObjectsUsingBlock:^(NSArray *columns, NSUInteger rowIdx, BOOL *stop) { 311 | NSMutableString *output = [NSMutableString string]; 312 | [columns enumerateObjectsUsingBlock:^(NSString *column, NSUInteger colIdx, BOOL *stop) { 313 | [output appendFormat:@"%@ ", column]; 314 | if (colIdx == 1) { 315 | NSUInteger length = column.length; 316 | while (length < maxNameTypeLength) { 317 | [output appendString:@" "]; 318 | length++; 319 | } 320 | } 321 | }]; 322 | printf("%s\n", output.UTF8String); 323 | }]; 324 | 325 | // Render footer. 326 | [self replacePlaceholdersAndPrintStringFromBlock:self.printHelpFooter]; 327 | } 328 | 329 | #pragma mark - Application information 330 | 331 | - (NSString *)applicationNameFromBlockOrDefault { 332 | if (self.applicationName) return self.applicationName(); 333 | NSProcessInfo *process = [NSProcessInfo processInfo]; 334 | return process.processName; 335 | } 336 | 337 | - (NSString *)applicationVersionFromBlockOrNil { 338 | if (self.applicationVersion) return self.applicationVersion(); 339 | return nil; 340 | } 341 | 342 | - (NSString *)applicationBuildFromBlockOrNil { 343 | if (self.applicationBuild) return self.applicationBuild(); 344 | return nil; 345 | } 346 | 347 | #pragma mark - Rendering helpers 348 | 349 | - (void)replacePlaceholdersAndPrintStringFromBlock:(GBOptionStringBlock)block { 350 | if (!block) { 351 | printf("\n"); 352 | return; 353 | } 354 | NSString *string = block(); 355 | if (self.applicationBuildFromBlockOrNil) 356 | string = [string stringByReplacingOccurrencesOfString:@"%APPNAME" withString:self.applicationNameFromBlockOrDefault]; 357 | if (self.applicationVersionFromBlockOrNil) 358 | string = [string stringByReplacingOccurrencesOfString:@"%APPVERSION" withString:self.applicationVersionFromBlockOrNil]; 359 | if (self.applicationBuildFromBlockOrNil) 360 | string = [string stringByReplacingOccurrencesOfString:@"%APPBUILD" withString:self.applicationBuildFromBlockOrNil]; 361 | printf("%s\n", string.UTF8String); 362 | } 363 | 364 | #pragma mark - Helper methods 365 | 366 | - (void)enumerateOptions:(void(^)(OptionDefinition *definition, BOOL *stop))handler { 367 | [self.registeredOptions enumerateObjectsUsingBlock:^(OptionDefinition *definition, NSUInteger idx, BOOL *stop) { 368 | handler(definition, stop); 369 | }]; 370 | } 371 | 372 | - (NSUInteger)requirements:(OptionDefinition *)definition { 373 | return (definition.flags & 0b11); 374 | } 375 | 376 | - (BOOL)isSeparator:(OptionDefinition *)definition { 377 | return ((definition.flags & GBOptionSeparator) > 0); 378 | } 379 | 380 | - (BOOL)isOptionGroup:(OptionDefinition *)definition { 381 | return ((definition.flags & GBOptionGroup) > 0); 382 | } 383 | 384 | - (BOOL)isOptionGroupEnd:(OptionDefinition *)definition { 385 | return ((definition.flags & GBOptionInternalEndGroup) > 0); 386 | } 387 | 388 | - (BOOL)isCmdLine:(OptionDefinition *)definition { 389 | return ((definition.flags & GBOptionNoCmdLine) == 0); 390 | } 391 | 392 | - (BOOL)isPrint:(OptionDefinition *)definition { 393 | return ((definition.flags & GBOptionNoPrint) == 0); 394 | } 395 | 396 | - (BOOL)isHelp:(OptionDefinition *)definition { 397 | return ((definition.flags & GBOptionNoHelp) == 0); 398 | } 399 | 400 | @end 401 | 402 | #pragma mark - 403 | 404 | @implementation GBCommandLineParser (GBOptionsHelper) 405 | 406 | - (void)registerOptions:(GBOptionsHelper *)options { 407 | [options registerOptionsToCommandLineParser:self]; 408 | } 409 | 410 | @end 411 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBPrint.h: -------------------------------------------------------------------------------- 1 | // 2 | // GBPrint.h 3 | // GBCli 4 | // 5 | // Created by Tomaz Kragelj on 23.05.14. 6 | // 7 | // 8 | 9 | #import 10 | 11 | extern void gbprint(NSString *format, ...); 12 | extern void gbprintln(NSString *format, ...); 13 | extern void gbfprint(FILE *file, NSString *format, ...); 14 | extern void gbfprintln(FILE *file, NSString *format, ...); 15 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBPrint.m: -------------------------------------------------------------------------------- 1 | // 2 | // GBPrint.m 3 | // GBCli 4 | // 5 | // Created by Tomaz Kragelj on 23.05.14. 6 | // 7 | // 8 | 9 | #import "GBPrint.h" 10 | 11 | static void gb_printf_worker(FILE *file, NSString *format, va_list arguments) { 12 | NSString *msg = [[NSString alloc] initWithFormat:format arguments:arguments]; 13 | fprintf(file, "%s", [msg UTF8String]); 14 | } 15 | 16 | void gbprint(NSString *format, ...) { 17 | va_list arguments; 18 | va_start(arguments, format); 19 | gb_printf_worker(stdout, format, arguments); 20 | va_end(arguments); 21 | } 22 | 23 | void gbprintln(NSString *format, ...) { 24 | va_list arguments; 25 | va_start(arguments, format); 26 | format = [format stringByAppendingString:@"\n"]; 27 | gb_printf_worker(stdout, format, arguments); 28 | va_end(arguments); 29 | } 30 | 31 | void gbfprint(FILE *file, NSString *format, ...) { 32 | va_list arguments; 33 | va_start(arguments, format); 34 | gb_printf_worker(file, format, arguments); 35 | va_end(arguments); 36 | } 37 | 38 | void gbfprintln(FILE *file, NSString *format, ...) { 39 | va_list arguments; 40 | va_start(arguments, format); 41 | format = [format stringByAppendingString:@"\n"]; 42 | gb_printf_worker(file, format, arguments); 43 | va_end(arguments); 44 | } 45 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBSettings.h: -------------------------------------------------------------------------------- 1 | // 2 | // GBSettings.h 3 | // GBCli 4 | // 5 | // Created by Tomaž Kragelj on 3/13/12. 6 | // Copyright (c) 2012 Tomaz Kragelj. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** The main application settings. 12 | 13 | This class declares all possible settings for the rest of the application. It supports building a hierarchy of settings levels, for example: factory defaults, settings file and command line arguments. It provides methods for accessing any given setting, which will automatically descend to parent if current level doesn't provide a value. If no level provides a value, methods will fail! Example of usage: 14 | 15 | ``` 16 | // Initialize settings hierarchy 17 | GBSettings *factoryDefaults = [GBSettings settingsWithName:@"FactoryDefaults" parent:nil]; 18 | GBSettings *fileSettings = [GBSettings settingsWithName:@"File" parent:factoryDefaults]; 19 | GBSettings *settings = [GBSettings settingsWithName:@"CommandLine" parent:fileSettings]; 20 | 21 | // Setup default values 22 | [factoryDefaults setObject:@"Some value" forKey:@"MyString"]; 23 | [factoryDefaults setInteger:50 forKey:@"MyInteger"]; 24 | [factoryDefaults setBool:YES forKey:@"MyBool"]; 25 | [fileSettings setInteger:12 forKey:@"MyInteger"]; 26 | [settings setInteger:20 forKey:@"MyInteger"]; 27 | [settings setBool:NO forKey:@"MyBool"]; 28 | ... from here on, just use settings... 29 | 30 | // Access values 31 | NSString *s = [settings objectForKey:@"MyString"]; // @"Some value" 32 | NSInteger i = [settings integerForKey:@"MyInteger"]; // 20 33 | BOOL b = [settings boolForKey:@"MyBool"]; // NO 34 | 35 | // Determine which level certain setting comes from 36 | GBSettings *s = [settings settingsForKey:@"MyString"]; // factoryDefaults 37 | ``` 38 | */ 39 | @interface GBSettings : NSObject 40 | 41 | #pragma mark - Initialization & disposal 42 | 43 | + (instancetype)settingsWithName:(NSString *)name parent:(GBSettings *)parent; 44 | - (instancetype)initWithName:(NSString *)name parent:(GBSettings *)parent; 45 | 46 | #pragma mark - Settings serialization support 47 | 48 | - (BOOL)loadSettingsFromPlist:(NSString *)path error:(NSError **)error; 49 | - (BOOL)saveSettingsToPlist:(NSString *)path error:(NSError **)error; 50 | 51 | #pragma mark - Values handling 52 | 53 | - (id)objectForKey:(NSString *)key; 54 | - (void)setObject:(id)value forKey:(NSString *)key; 55 | 56 | - (BOOL)boolForKey:(NSString *)key; 57 | - (void)setBool:(BOOL)value forKey:(NSString *)key; 58 | 59 | - (NSInteger)integerForKey:(NSString *)key; 60 | - (void)setInteger:(NSInteger)value forKey:(NSString *)key; 61 | 62 | - (NSUInteger)unsignedIntegerForKey:(NSString *)key; 63 | - (void)setUnsignedInteger:(NSUInteger)value forKey:(NSString *)key; 64 | 65 | - (CGFloat)floatForKey:(NSString *)key; 66 | - (void)setFloat:(CGFloat)value forKey:(NSString *)key; 67 | 68 | #pragma mark - Arguments handling 69 | 70 | - (void)addArgument:(NSString *)argument; 71 | - (GBSettings *)settingsForArgument:(NSString *)argument; 72 | @property (nonatomic, strong) NSArray *arguments; 73 | 74 | #pragma mark - Registration & low level handling 75 | 76 | - (void)registerArrayForKey:(NSString *)key; 77 | - (id)objectForLocalKey:(NSString *)key; 78 | - (void)setObject:(id)value forLocalKey:(NSString *)key; 79 | 80 | #pragma mark - Introspection 81 | 82 | - (void)enumerateSettings:(void(^)(GBSettings *settings, BOOL *stop))handler; 83 | - (GBSettings *)settingsForArrayValue:(NSString *)value key:(NSString *)key; 84 | - (GBSettings *)settingsForKey:(NSString *)key; 85 | - (BOOL)isKeyPresentAtThisLevel:(NSString *)key; 86 | - (BOOL)isKeyArray:(NSString *)key; 87 | 88 | #pragma mark - Properties 89 | 90 | @property (nonatomic, readonly, copy) NSString *name; 91 | @property (nonatomic, readonly, strong) GBSettings *parent; 92 | 93 | @end 94 | 95 | #pragma mark - Convenience one-line synthesize macros for concrete properties 96 | 97 | #define GB_SYNTHESIZE_PROPERTY(type, accessorSel, mutatorSel, valueAccessor, valueMutator, key, val) \ 98 | - (type)accessorSel { return [self valueAccessor:key]; } \ 99 | - (void)mutatorSel:(type)value { [self valueMutator:val forKey:key]; } 100 | #define GB_SYNTHESIZE_OBJECT(type, accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(type, accessorSel, mutatorSel, objectForKey, setObject, key, value) 101 | #define GB_SYNTHESIZE_COPY(type, accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(type, accessorSel, mutatorSel, objectForKey, setObject, key, [value copy]) 102 | #define GB_SYNTHESIZE_BOOL(accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(BOOL, accessorSel, mutatorSel, boolForKey, setBool, key, value) 103 | #define GB_SYNTHESIZE_INT(accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(NSInteger, accessorSel, mutatorSel, integerForKey, setInteger, key, value) 104 | #define GB_SYNTHESIZE_UINT(accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(NSUInteger, accessorSel, mutatorSel, unsignedIntegerForKey, setUnsignedInteger, key, value) 105 | #define GB_SYNTHESIZE_FLOAT(accessorSel, mutatorSel, key) GB_SYNTHESIZE_PROPERTY(CGFloat, accessorSel, mutatorSel, floatForKey, setFloat, key, value) 106 | -------------------------------------------------------------------------------- /Pods/GBCli/GBCli/src/GBSettings.m: -------------------------------------------------------------------------------- 1 | 2 | // GBSettings.m 3 | // GBCli 4 | // 5 | // Created by Tomaž Kragelj on 3/13/12. 6 | // Copyright (c) 2012 Tomaz Kragelj. All rights reserved. 7 | // 8 | 9 | #import "GBSettings.h" 10 | 11 | static NSString * const GBSettingsArgumentsKey = @"B450A340-EC4F-40EC-B18D-B52DB881A16A"; 12 | 13 | #pragma mark - 14 | 15 | @interface GBSettings () 16 | @property (nonatomic, readwrite, copy) NSString *name; 17 | @property (nonatomic, readwrite, strong) GBSettings *parent; 18 | @property (nonatomic, strong) NSMutableSet *arrayKeys; 19 | @property (nonatomic, strong) NSMutableDictionary *storage; 20 | @end 21 | 22 | #pragma mark - 23 | 24 | @implementation GBSettings 25 | 26 | #pragma mark - Initialization & disposal 27 | 28 | + (instancetype)settingsWithName:(NSString *)name parent:(GBSettings *)parent { 29 | return [[self alloc] initWithName:name parent:parent]; 30 | } 31 | 32 | - (instancetype)initWithName:(NSString *)name parent:(GBSettings *)parent { 33 | self = [super init]; 34 | if (self) { 35 | self.name = name; 36 | self.parent = parent; 37 | self.arrayKeys = [NSMutableSet set]; 38 | self.storage = [NSMutableDictionary dictionary]; 39 | [self registerArrayForKey:GBSettingsArgumentsKey]; 40 | } 41 | return self; 42 | } 43 | 44 | #pragma mark - Settings serialization support 45 | 46 | - (BOOL)loadSettingsFromPlist:(NSString *)path error:(NSError **)error { 47 | NSFileManager *manager = [NSFileManager defaultManager]; 48 | if (![manager fileExistsAtPath:path]) return NO; 49 | 50 | // Load data into dictionary. 51 | NSData* data = [NSData dataWithContentsOfFile:path options:0 error:error]; 52 | if (!data) return NO; 53 | NSDictionary *values = [NSPropertyListSerialization propertyListWithData:data options:NSPropertyListImmutable format:NULL error:error]; 54 | if (!values) return NO; 55 | 56 | // Prepare block that will handle individual key. 57 | void(^handleKey)(NSString *, id) = ^(NSString *key, id value) { 58 | while ([key hasPrefix:@"-"]) key = [key substringFromIndex:1]; 59 | [self setObject:value forKey:key]; 60 | }; 61 | 62 | // Copy all values to ourself. Remove - or -- prefix which can optionally be used in the file! 63 | [self.storage removeAllObjects]; 64 | [values enumerateKeysAndObjectsUsingBlock:^(NSString *key, id value, BOOL *stop) { 65 | if ([value isKindOfClass:[NSDictionary class]]) { 66 | [value enumerateKeysAndObjectsUsingBlock:^(NSString *valueKey, id valueValue, BOOL *stop) { 67 | handleKey(valueKey, valueValue); 68 | }]; 69 | return; 70 | } 71 | handleKey(key, value); 72 | }]; 73 | return YES; 74 | } 75 | 76 | - (BOOL)saveSettingsToPlist:(NSString *)path error:(NSError **)error { 77 | // Note that we only save settings from current level! 78 | NSData *data = [NSPropertyListSerialization dataWithPropertyList:self.storage format:NSPropertyListXMLFormat_v1_0 options:0 error:error]; 79 | if (!data) return NO; 80 | return [data writeToFile:path options:NSDataWritingAtomic error:error]; 81 | } 82 | 83 | #pragma mark - Values handling 84 | 85 | - (id)objectForKey:(NSString *)key { 86 | if ([self isKeyArray:key]) { 87 | NSMutableArray *allValues = [NSMutableArray array]; 88 | GBSettings *settings = self; 89 | while (settings) { 90 | NSArray *currentLevelValues = [settings objectForLocalKey:key]; 91 | [allValues addObjectsFromArray:currentLevelValues]; 92 | settings = settings.parent; 93 | } 94 | return allValues; 95 | } 96 | GBSettings *level = [self settingsForKey:key]; 97 | return [level objectForLocalKey:key]; 98 | } 99 | - (void)setObject:(id)value forKey:(NSString *)key { 100 | if ([self isKeyArray:key] && ![key isKindOfClass:[NSArray class]]) { 101 | NSMutableArray *array = [self.storage objectForKey:key]; 102 | if (![array isKindOfClass:[NSMutableArray class]]) { 103 | id existing = array; 104 | array = [NSMutableArray array]; 105 | if (existing) [array addObject:existing]; 106 | [self setObject:array forLocalKey:key]; 107 | } 108 | if ([value isKindOfClass:[NSArray class]]) 109 | [array addObjectsFromArray:value]; 110 | else 111 | [array addObject:value]; 112 | return; 113 | } 114 | [self setObject:value forLocalKey:key]; 115 | } 116 | 117 | - (BOOL)boolForKey:(NSString *)key { 118 | NSNumber *number = [self objectForKey:key]; 119 | return [number boolValue]; 120 | } 121 | - (void)setBool:(BOOL)value forKey:(NSString *)key { 122 | [self setObject:@(value) forKey:key]; 123 | } 124 | 125 | - (NSInteger)integerForKey:(NSString *)key { 126 | NSNumber *number = [self objectForKey:key]; 127 | return [number integerValue]; 128 | } 129 | - (void)setInteger:(NSInteger)value forKey:(NSString *)key { 130 | [self setObject:@(value) forKey:key]; 131 | } 132 | 133 | - (NSUInteger)unsignedIntegerForKey:(NSString *)key { 134 | NSNumber *number = [self objectForKey:key]; 135 | return (NSUInteger)[number integerValue]; 136 | } 137 | - (void)setUnsignedInteger:(NSUInteger)value forKey:(NSString *)key { 138 | [self setObject:@(value) forKey:key]; 139 | } 140 | 141 | - (CGFloat)floatForKey:(NSString *)key { 142 | NSNumber *number = [self objectForKey:key]; 143 | return [number doubleValue]; 144 | } 145 | - (void)setFloat:(CGFloat)value forKey:(NSString *)key { 146 | [self setObject:@(value) forKey:key]; 147 | } 148 | 149 | #pragma mark - Arguments handling 150 | 151 | - (void)addArgument:(NSString *)argument { 152 | [self setObject:argument forKey:GBSettingsArgumentsKey]; 153 | } 154 | 155 | - (GBSettings *)settingsForArgument:(NSString *)argument { 156 | return [self settingsForArrayValue:argument key:GBSettingsArgumentsKey]; 157 | } 158 | 159 | GB_SYNTHESIZE_OBJECT(NSArray *, arguments, setArguments, GBSettingsArgumentsKey) 160 | 161 | #pragma mark - Registration & low level handling 162 | 163 | - (void)registerArrayForKey:(NSString *)key { 164 | [self.arrayKeys addObject:key]; 165 | } 166 | 167 | - (id)objectForLocalKey:(NSString *)key { 168 | return [self.storage objectForKey:key]; 169 | } 170 | - (void)setObject:(id)value forLocalKey:(NSString *)key { 171 | [self.storage setObject:value forKey:key]; 172 | } 173 | 174 | #pragma mark - Introspection 175 | 176 | - (void)enumerateSettings:(void(^)(GBSettings *settings, BOOL *stop))handler { 177 | GBSettings *settings = self; 178 | BOOL stop = NO; 179 | while (settings) { 180 | handler(settings, &stop); 181 | if (stop) break; 182 | settings = settings.parent; 183 | } 184 | } 185 | 186 | - (GBSettings *)settingsForArrayValue:(NSString *)value key:(NSString *)key { 187 | __block GBSettings *result = nil; 188 | [self enumerateSettings:^(GBSettings *settings, BOOL *stop) { 189 | NSArray *arguments = [settings objectForLocalKey:key]; 190 | if ([arguments containsObject:value]) { 191 | result = settings; 192 | *stop = YES; 193 | } 194 | }]; 195 | return result; 196 | } 197 | 198 | - (GBSettings *)settingsForKey:(NSString *)key { 199 | __block GBSettings *result = nil; 200 | [self enumerateSettings:^(GBSettings *settings, BOOL *stop) { 201 | if ([settings isKeyPresentAtThisLevel:key]) { 202 | result = settings; 203 | *stop = YES; 204 | } 205 | }]; 206 | return result; 207 | } 208 | 209 | - (BOOL)isKeyPresentAtThisLevel:(NSString *)key { 210 | if ([self.storage objectForKey:key]) return YES; 211 | return NO; 212 | } 213 | 214 | - (BOOL)isKeyArray:(NSString *)key { 215 | return [self.arrayKeys containsObject:key]; 216 | } 217 | 218 | @end 219 | -------------------------------------------------------------------------------- /Pods/GBCli/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 by Tomaz Kragelj 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Pods/GBCli/Readme.markdown: -------------------------------------------------------------------------------- 1 | GBCli 2 | ----- 3 | 4 | GBCli is command line interface helper library. It provides classes for simplifying command line Objective C foundation tools code. The library is designed to be as flexible as possible to suit wide range of tools. It requires no external dependency besides *Foundation.framework*. The library was inspired by [DDCli](http://www.dribin.org/dave/software/#ddcli) by Dave Dribin. 5 | 6 | Here's how it happened (skip this part if you're only interested in techical stuff :) - When I started work on redesigning [appledoc](http://gentlebytes.com/appledoc), one of the first files I included was DDCli library. However I soon discovered it doesn't work well with arc. That, coupled with different workflow I wanted, prompted me to dig in Dave's code to see how I could change it to suit my needs better. To cut long story short - at the end I ended writing the whole library from scratch and now parsing is implemented manually, without relying on `getopt_long`. As I was adding more functionality, I realized, I could make it as reusable component and publish it on GitHub... 7 | 8 | This file serves as tutorial demonstrating what you can do with the library. 9 | 10 | 11 | Integrating to your project 12 | --------------------------- 13 | 14 | The simplest way of integrating GBCli is through cocoapods. Just add this line to your Podfile: 15 | 16 | ``` 17 | pod "GBCli" 18 | ``` 19 | 20 | Then import all files so compiler can see them: `#import `. 21 | 22 | If you prefer to include sources directly, just copy all .h and .m files from `GBCli/src` subfolder to your Xcode project and import `GBCli.h` header (in this case you'll probably need to use `#import "GBCli.h"`). 23 | 24 | 25 | Parsing command line arguments 26 | ------------------------------ 27 | 28 | The most basic building block of the library is parsing command line arguments. This is implemented with *GBCommandLineParser* class. To use it, you need to register all options first, then have it parse command line. Based on registered data, the class determines whether command line is valid or not. But that alone wouldn't be that useful, so the class also offers interface for getting the actual options and argument values. You can use callback API to be notified about each option and/or argument as it is parsed (**Note:** with *options* I refer to command line options such as `--verbose`, `--help` etc, while *arguments* are various arguments that follow the options such as paths to source files etc). 29 | 30 | Besides callback API, parser also stores all recognized options and arguments internally, so you can query it for values after parsing is complete. This can solve the problem with storing values. 31 | 32 | An example: 33 | 34 | ``` 35 | int main(int argc, char **argv) { 36 | // Create parser and register all options. 37 | GBCommandLineParser *parser = [[GBCommandLineParser alloc] init]; 38 | [parser registerOption:@"optiona" shortcut:'a' requirement:GBValueRequired]; 39 | [parser registerOption:@"optionb" shortcut:'b' requirement:GBValueOptional]; 40 | [parser registerOption:@"optionc" shortcut:'c' requirement:GBValueNone]; 41 | 42 | // Parse command line 43 | [parser parseOptionsWithArguments:argv count:argc block:^(GBParseFlags flags, NSString *option, id value, BOOL *stop) { 44 | switch (flags) { 45 | case GBParseFlagUnknownOption: 46 | printf("Unknown command line option %s, try --help!\n", [option UTF8String]); 47 | break; 48 | case GBParseFlagMissingValue: 49 | printf("Missing value for command line option %s, try --help!\n", [option UTF8String]); 50 | break; 51 | case GBParseFlagOption: 52 | // do something with 'option' and its 'value' 53 | break; 54 | case GBParseFlagArgument: 55 | // do something with argument 'value' 56 | break; 57 | } 58 | }]; 59 | ... 60 | // Now that parsing is complete, you can access options and arguments: 61 | id valuea = [parser valueForOption:@"optiona"]; 62 | NSArray *arguments = parser.arguments; 63 | ... 64 | } 65 | ``` 66 | 67 | In above example, we've registered 3 options: 68 | 69 | - `--optiona` with shortcut `-a` as a required value. 70 | - `--optionb` with shortcut `-b` as an optional value. 71 | - `--optionc` with shortcut `-c` and no value. 72 | 73 | You can also register only long option, without short variant - just pass `0` for the short option argument. As you can see you can specify each option's value as required, optional or no value. Here's how it works: 74 | 75 | - *Required values:* the option must be followed by a value like this: `--optiona value`, `-a value` or alternatively `--optiona=value` or `-a=value` (in later case there must be no space in between the option name, equal sign and the value!). If value is missing, parser will report missing value via *GBParseFlagMissingValue* flag. Note that you need to embed strings with whitespaces into quotes like this: `--some-option "My whitespaced string"`. 76 | - *Optional values:* the value is optional, so all of these are valid: `--optionb value`, `-b value`, `--optionb=value`, `-b=value`. In these cases, the given value is reported as a *NSString*. Additionally, you can also omit the value altogether: `--optionb` or `-b`. In this case, *NSNumber* setup as `@YES` is reported to block as long as the option is provided on command line. 77 | - *No value:* the option is a "command line boolean switch". If the option is found on command line (for example `--optionc` or `-c`) it is assumed as "enabled" and an `[NSNumber numberWithBool:YES]` is reported as its value in parsing block. These options can also use negated syntax in the form `--no-