Index: ObjFW.xcodeproj/project.pbxproj ================================================================== --- ObjFW.xcodeproj/project.pbxproj +++ ObjFW.xcodeproj/project.pbxproj @@ -353,10 +353,12 @@ 4BA85BCE140ECCE800E91D51 /* OFSet_hashtable.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA85BC8140ECCE800E91D51 /* OFSet_hashtable.h */; }; 4BA85BCF140ECCE800E91D51 /* OFSet_hashtable.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BA85BC9140ECCE800E91D51 /* OFSet_hashtable.m */; }; 4BA9CFA415E129D30076DC74 /* autorelease.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BA9CFA315E129D30076DC74 /* autorelease.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BAA60C814D09699006F068D /* OFJSONTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BAA60C714D09699006F068D /* OFJSONTests.m */; }; 4BAE7354139C508E00F682ED /* serialization.xml in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4BAE7353139C507F00F682ED /* serialization.xml */; }; + 4BAFC168182EAA7800BE5E57 /* OFOptionsParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BAFC166182EAA7800BE5E57 /* OFOptionsParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4BAFC169182EAA7800BE5E57 /* OFOptionsParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BAFC167182EAA7800BE5E57 /* OFOptionsParser.m */; }; 4BB25E88139C388A00F574EA /* OFObject+Serialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB25E82139C388A00F574EA /* OFObject+Serialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB25E89139C388A00F574EA /* OFObject+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB25E83139C388A00F574EA /* OFObject+Serialization.m */; }; 4BB25E8A139C388A00F574EA /* OFString+Serialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB25E84139C388A00F574EA /* OFString+Serialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4BB25E8B139C388A00F574EA /* OFString+Serialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB25E85139C388A00F574EA /* OFString+Serialization.m */; }; 4BB25E8C139C388A00F574EA /* OFXMLElement+Serialization.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BB25E86139C388A00F574EA /* OFXMLElement+Serialization.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -798,10 +800,12 @@ 4BAF5F46123460C900F4E111 /* OFCollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFCollection.h; path = src/OFCollection.h; sourceTree = ""; }; 4BAF5F47123460C900F4E111 /* OFStreamObserver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamObserver.h; path = src/OFStreamObserver.h; sourceTree = ""; }; 4BAF5F48123460C900F4E111 /* OFStreamObserver.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamObserver.m; path = src/OFStreamObserver.m; sourceTree = ""; }; 4BAF5F49123460C900F4E111 /* OFStreamSocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFStreamSocket.h; path = src/OFStreamSocket.h; sourceTree = ""; }; 4BAF5F4A123460C900F4E111 /* OFStreamSocket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFStreamSocket.m; path = src/OFStreamSocket.m; sourceTree = ""; }; + 4BAFC166182EAA7800BE5E57 /* OFOptionsParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OFOptionsParser.h; path = src/OFOptionsParser.h; sourceTree = ""; }; + 4BAFC167182EAA7800BE5E57 /* OFOptionsParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OFOptionsParser.m; path = src/OFOptionsParser.m; sourceTree = ""; }; 4BB25E82139C388A00F574EA /* OFObject+Serialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFObject+Serialization.h"; path = "src/OFObject+Serialization.h"; sourceTree = ""; }; 4BB25E83139C388A00F574EA /* OFObject+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFObject+Serialization.m"; path = "src/OFObject+Serialization.m"; sourceTree = ""; }; 4BB25E84139C388A00F574EA /* OFString+Serialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFString+Serialization.h"; path = "src/OFString+Serialization.h"; sourceTree = ""; }; 4BB25E85139C388A00F574EA /* OFString+Serialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OFString+Serialization.m"; path = "src/OFString+Serialization.m"; sourceTree = ""; }; 4BB25E86139C388A00F574EA /* OFXMLElement+Serialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OFXMLElement+Serialization.h"; path = "src/OFXMLElement+Serialization.h"; sourceTree = ""; }; @@ -1222,10 +1226,12 @@ 4B6799761099E7C50041064A /* OFNumber.m */, 4B6799771099E7C50041064A /* OFObject.h */, 4B6799781099E7C50041064A /* OFObject.m */, 4BB25E82139C388A00F574EA /* OFObject+Serialization.h */, 4BB25E83139C388A00F574EA /* OFObject+Serialization.m */, + 4BAFC166182EAA7800BE5E57 /* OFOptionsParser.h */, + 4BAFC167182EAA7800BE5E57 /* OFOptionsParser.m */, 4B6799791099E7C50041064A /* OFPlugin.h */, 4B67997A1099E7C50041064A /* OFPlugin.m */, 4BB524BF143D1E4E0085FBCC /* OFProcess.h */, 4BB524C0143D1E4E0085FBCC /* OFProcess.m */, 4B6743FC163C395900EB1E59 /* OFRecursiveMutex.h */, @@ -1491,10 +1497,11 @@ 4B674403163C395900EB1E59 /* OFMutex.h in Headers */, 4B511B7C139C0A34003764A5 /* OFNull.h in Headers */, 4B3D23D01337FCB000DD29B8 /* OFNumber.h in Headers */, 4B3D23D11337FCB000DD29B8 /* OFObject.h in Headers */, 4BB25E88139C388A00F574EA /* OFObject+Serialization.h in Headers */, + 4BAFC168182EAA7800BE5E57 /* OFOptionsParser.h in Headers */, 4B3D23D21337FCB000DD29B8 /* OFPlugin.h in Headers */, 4BB524C1143D1E4E0085FBCC /* OFProcess.h in Headers */, 4B674405163C395900EB1E59 /* OFRecursiveMutex.h in Headers */, 4B325EDD1605F3A0007836CA /* OFRunLoop.h in Headers */, 4B3D23D31337FCB000DD29B8 /* OFSeekableStream.h in Headers */, @@ -1856,10 +1863,11 @@ 4B674404163C395900EB1E59 /* OFMutex.m in Sources */, 4B511B7D139C0A34003764A5 /* OFNull.m in Sources */, 4B3D239E1337FC0D00DD29B8 /* OFNumber.m in Sources */, 4B3D239F1337FC0D00DD29B8 /* OFObject.m in Sources */, 4BB25E89139C388A00F574EA /* OFObject+Serialization.m in Sources */, + 4BAFC169182EAA7800BE5E57 /* OFOptionsParser.m in Sources */, 4B3D23A01337FC0D00DD29B8 /* OFPlugin.m in Sources */, 4BB524C2143D1E4E0085FBCC /* OFProcess.m in Sources */, 4B674406163C395900EB1E59 /* OFRecursiveMutex.m in Sources */, 4B325EDE1605F3A0007836CA /* OFRunLoop.m in Sources */, 4B3D23A11337FC0D00DD29B8 /* OFSeekableStream.m in Sources */, Index: src/Makefile ================================================================== --- src/Makefile +++ src/Makefile @@ -34,10 +34,11 @@ OFMutableString.m \ OFNull.m \ OFNumber.m \ OFObject.m \ OFObject+Serialization.m \ + OFOptionsParser.m \ ${OFPROCESS_M} \ OFRunLoop.m \ OFSeekableStream.m \ OFSet.m \ OFSHA1Hash.m \ ADDED src/OFOptionsParser.h Index: src/OFOptionsParser.h ================================================================== --- src/OFOptionsParser.h +++ src/OFOptionsParser.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#import "OFObject.h" +#import "OFConstantString.h" + +/*! + * @brief A class for parsing the program options specified on the command line. + */ +@interface OFOptionsParser: OFObject +{ + of_unichar_t *_options; + OFArray *_arguments; + size_t _index, _subIndex; + of_unichar_t _lastOption; + OFString *_argument; + bool _done; +} + +/*! + * @brief Creates a new OFOptionsParser which accepts the specified options. + * + * @param options A string listing the acceptable options.@n + * Options that require an argument are immediately followed by + * ':'. + * + * @return A new, autoreleased OFOptionsParser + */ ++ (instancetype)parserWithOptions: (OFString*)options; + +/*! + * @brief Initializes an already allocated OFOptionsParser so that it accepts + * the specified options. + * + * @param options A string listing the acceptable options.@n + * Options that require an argument are immediately followed by + * ':'. + * + * @return An initialized OFOptionsParser + */ +- initWithOptions: (OFString*)options; + +/*! + * @brief Returns the next option. + * + * If an unknown option is specified, '?' is returned.@n + * If the argument for the option is missing, ':' is returned.@n + * If all options have been parsed, '\0' is returned. + * + * @return The next option + */ +- (of_unichar_t)nextOption; + +/*! + * @brief Returns the last parsed option. + * + * If @ref nextOption returned '?' or ':', this returns the option which was + * unknown or for which the argument was missing. + * + * @return The last parsed option + */ +- (of_unichar_t)lastOption; + +/*! + * @brief Returns the argument for the last parsed option, or nil if the last + * parsed option takes no argument. + * + * @return The argument for the last parsed option + */ +- (OFString*)argument; + +/*! + * @brief Returns the arguments following the last option. + * + * @return The arguments following the last option + */ +- (OFArray*)remainingArguments; +@end ADDED src/OFOptionsParser.m Index: src/OFOptionsParser.m ================================================================== --- src/OFOptionsParser.m +++ src/OFOptionsParser.m @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 + * Jonathan Schleifer + * + * All rights reserved. + * + * This file is part of ObjFW. It may be distributed under the terms of the + * Q Public License 1.0, which can be found in the file LICENSE.QPL included in + * the packaging of this file. + * + * Alternatively, it may be distributed under the terms of the GNU General + * Public License, either version 2 or 3, which can be found in the file + * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this + * file. + */ + +#include "config.h" + +#include + +#import "OFOptionsParser.h" +#import "OFApplication.h" +#import "OFArray.h" + +#import "autorelease.h" +#import "macros.h" + +@implementation OFOptionsParser ++ (instancetype)parserWithOptions: (OFString*)options +{ + return [[[self alloc] initWithOptions: options] autorelease]; +} + +- init +{ + @try { + [self doesNotRecognizeSelector: _cmd]; + } @catch (id e) { + [self release]; + @throw e; + } + + abort(); +} + +- initWithOptions: (OFString*)options +{ + self = [super init]; + + @try { + _options = [self allocMemoryWithSize: sizeof(of_unichar_t) + count: [options length] + 1]; + [options getCharacters: _options + inRange: of_range(0, [options length])]; + _options[[options length]] = 0; + + _arguments = [[OFApplication arguments] retain]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_arguments release]; + [_argument release]; + + [super dealloc]; +} + +- (of_unichar_t)nextOption +{ + of_unichar_t *options; + OFString *argument; + + if (_done || _index >= [_arguments count]) + return '\0'; + + argument = [_arguments objectAtIndex: _index]; + + if (_subIndex == 0) { + if ([argument length] < 2 || + [argument characterAtIndex: 0] != '-') { + _done = true; + return '\0'; + } + + if ([argument isEqual: @"--"]) { + _done = true; + _index++; + return '\0'; + } + + _subIndex = 1; + } + + _lastOption = [argument characterAtIndex: _subIndex++]; + + if (_subIndex >= [argument length]) { + _index++; + _subIndex = 0; + } + + for (options = _options; *options != 0; options++) { + if (_lastOption == *options) { + if (options[1] != ':') { + [_argument release]; + _argument = nil; + return _lastOption; + } + + if (_index >= [_arguments count]) + return ':'; + + argument = [_arguments objectAtIndex: _index]; + argument = [argument substringWithRange: + of_range(_subIndex, [argument length] - _subIndex)]; + + [_argument release]; + _argument = [argument copy]; + + _index++; + _subIndex = 0; + + return _lastOption; + } + } + + return '?'; +} + +- (of_unichar_t)lastOption +{ + return _lastOption; +} + +- (OFString*)argument +{ + return [[_argument copy] autorelease]; +} + +- (OFArray*)remainingArguments +{ + return [_arguments objectsInRange: + of_range(_index, [_arguments count] - _index)]; +} +@end Index: src/ObjFW.h ================================================================== --- src/ObjFW.h +++ src/ObjFW.h @@ -81,10 +81,11 @@ #import "OFXMLElementBuilder.h" #import "OFMessagePackExtension.h" #import "OFApplication.h" +#import "OFOptionsParser.h" #import "OFSystemInfo.h" #import "OFTimer.h" #import "OFRunLoop.h" #import "OFAllocFailedException.h"