├── .gitignore ├── DictionaryOSX.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── DictionaryOSX.xcscheme ├── DictionaryOSX ├── Dictionary.swift ├── DictionaryOSX-Bridging-Header.h └── main.swift ├── Frameworks ├── CommandLine │ ├── CommandLine.swift │ ├── Info.plist │ ├── LICENSE │ ├── Option.swift │ └── StringExtensions.swift └── DictionaryKit │ ├── DictionaryKit.xcworkspace │ └── contents.xcworkspacedata │ ├── DictionaryKit │ ├── DictionaryKit.h │ ├── TTTDictionary.h │ └── TTTDictionary.m │ ├── Example │ ├── DictionaryKit Example.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ ├── Prefix.pch │ └── main.m │ ├── LICENSE │ └── README.md └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | DerivedData/ 3 | *.xcuserstate 4 | *.xcuserdatad 5 | -------------------------------------------------------------------------------- /DictionaryOSX.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4FA13A481DE1F884009C3448 /* CommandLine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA13A431DE1F884009C3448 /* CommandLine.swift */; }; 11 | 4FA13A491DE1F884009C3448 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA13A461DE1F884009C3448 /* Option.swift */; }; 12 | 4FA13A4A1DE1F884009C3448 /* StringExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA13A471DE1F884009C3448 /* StringExtensions.swift */; }; 13 | 4FA13A4C1DE1FE32009C3448 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA13A4B1DE1FE32009C3448 /* Dictionary.swift */; }; 14 | 4FA939AC1DE1DA0000D45D48 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4FA939AB1DE1DA0000D45D48 /* main.swift */; }; 15 | 4FA939C81DE1DEE200D45D48 /* TTTDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FA939B81DE1DBD600D45D48 /* TTTDictionary.m */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXCopyFilesBuildPhase section */ 19 | 4FA939A61DE1DA0000D45D48 /* CopyFiles */ = { 20 | isa = PBXCopyFilesBuildPhase; 21 | buildActionMask = 2147483647; 22 | dstPath = /usr/share/man/man1/; 23 | dstSubfolderSpec = 0; 24 | files = ( 25 | ); 26 | runOnlyForDeploymentPostprocessing = 1; 27 | }; 28 | /* End PBXCopyFilesBuildPhase section */ 29 | 30 | /* Begin PBXFileReference section */ 31 | 4FA13A431DE1F884009C3448 /* CommandLine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommandLine.swift; sourceTree = ""; }; 32 | 4FA13A451DE1F884009C3448 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 33 | 4FA13A461DE1F884009C3448 /* Option.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Option.swift; sourceTree = ""; }; 34 | 4FA13A471DE1F884009C3448 /* StringExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringExtensions.swift; sourceTree = ""; }; 35 | 4FA13A4B1DE1FE32009C3448 /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; }; 36 | 4FA939A81DE1DA0000D45D48 /* dictionary */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dictionary; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 4FA939AB1DE1DA0000D45D48 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 38 | 4FA939B61DE1DBD600D45D48 /* DictionaryKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DictionaryKit.h; sourceTree = ""; }; 39 | 4FA939B71DE1DBD600D45D48 /* TTTDictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TTTDictionary.h; sourceTree = ""; }; 40 | 4FA939B81DE1DBD600D45D48 /* TTTDictionary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TTTDictionary.m; sourceTree = ""; }; 41 | 4FA939C51DE1DC5A00D45D48 /* DictionaryOSX-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DictionaryOSX-Bridging-Header.h"; sourceTree = ""; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 4FA939A51DE1DA0000D45D48 /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | ); 50 | runOnlyForDeploymentPostprocessing = 0; 51 | }; 52 | /* End PBXFrameworksBuildPhase section */ 53 | 54 | /* Begin PBXGroup section */ 55 | 4FA13A421DE1F884009C3448 /* CommandLine */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | 4FA13A431DE1F884009C3448 /* CommandLine.swift */, 59 | 4FA13A451DE1F884009C3448 /* LICENSE */, 60 | 4FA13A461DE1F884009C3448 /* Option.swift */, 61 | 4FA13A471DE1F884009C3448 /* StringExtensions.swift */, 62 | ); 63 | path = CommandLine; 64 | sourceTree = ""; 65 | }; 66 | 4FA9399F1DE1DA0000D45D48 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 4FA939B31DE1DBD600D45D48 /* Frameworks */, 70 | 4FA939AA1DE1DA0000D45D48 /* DictionaryOSX */, 71 | 4FA939A91DE1DA0000D45D48 /* Products */, 72 | ); 73 | sourceTree = ""; 74 | }; 75 | 4FA939A91DE1DA0000D45D48 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 4FA939A81DE1DA0000D45D48 /* dictionary */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | 4FA939AA1DE1DA0000D45D48 /* DictionaryOSX */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 4FA13A4B1DE1FE32009C3448 /* Dictionary.swift */, 87 | 4FA939C51DE1DC5A00D45D48 /* DictionaryOSX-Bridging-Header.h */, 88 | 4FA939AB1DE1DA0000D45D48 /* main.swift */, 89 | ); 90 | path = DictionaryOSX; 91 | sourceTree = ""; 92 | }; 93 | 4FA939B31DE1DBD600D45D48 /* Frameworks */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 4FA13A421DE1F884009C3448 /* CommandLine */, 97 | 4FA939B51DE1DBD600D45D48 /* DictionaryKit */, 98 | ); 99 | path = Frameworks; 100 | sourceTree = ""; 101 | }; 102 | 4FA939B51DE1DBD600D45D48 /* DictionaryKit */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 4FA939B61DE1DBD600D45D48 /* DictionaryKit.h */, 106 | 4FA939B71DE1DBD600D45D48 /* TTTDictionary.h */, 107 | 4FA939B81DE1DBD600D45D48 /* TTTDictionary.m */, 108 | ); 109 | name = DictionaryKit; 110 | path = DictionaryKit/DictionaryKit; 111 | sourceTree = ""; 112 | }; 113 | /* End PBXGroup section */ 114 | 115 | /* Begin PBXNativeTarget section */ 116 | 4FA939A71DE1DA0000D45D48 /* DictionaryOSX */ = { 117 | isa = PBXNativeTarget; 118 | buildConfigurationList = 4FA939AF1DE1DA0000D45D48 /* Build configuration list for PBXNativeTarget "DictionaryOSX" */; 119 | buildPhases = ( 120 | 4FA939A41DE1DA0000D45D48 /* Sources */, 121 | 4FA939A51DE1DA0000D45D48 /* Frameworks */, 122 | 4FA939A61DE1DA0000D45D48 /* CopyFiles */, 123 | ); 124 | buildRules = ( 125 | ); 126 | dependencies = ( 127 | ); 128 | name = DictionaryOSX; 129 | productName = DictionaryOSX; 130 | productReference = 4FA939A81DE1DA0000D45D48 /* dictionary */; 131 | productType = "com.apple.product-type.tool"; 132 | }; 133 | /* End PBXNativeTarget section */ 134 | 135 | /* Begin PBXProject section */ 136 | 4FA939A01DE1DA0000D45D48 /* Project object */ = { 137 | isa = PBXProject; 138 | attributes = { 139 | LastSwiftUpdateCheck = 0730; 140 | LastUpgradeCheck = 0730; 141 | ORGANIZATIONNAME = ODLP; 142 | TargetAttributes = { 143 | 4FA939A71DE1DA0000D45D48 = { 144 | CreatedOnToolsVersion = 7.3.1; 145 | }; 146 | }; 147 | }; 148 | buildConfigurationList = 4FA939A31DE1DA0000D45D48 /* Build configuration list for PBXProject "DictionaryOSX" */; 149 | compatibilityVersion = "Xcode 3.2"; 150 | developmentRegion = English; 151 | hasScannedForEncodings = 0; 152 | knownRegions = ( 153 | en, 154 | ); 155 | mainGroup = 4FA9399F1DE1DA0000D45D48; 156 | productRefGroup = 4FA939A91DE1DA0000D45D48 /* Products */; 157 | projectDirPath = ""; 158 | projectRoot = ""; 159 | targets = ( 160 | 4FA939A71DE1DA0000D45D48 /* DictionaryOSX */, 161 | ); 162 | }; 163 | /* End PBXProject section */ 164 | 165 | /* Begin PBXSourcesBuildPhase section */ 166 | 4FA939A41DE1DA0000D45D48 /* Sources */ = { 167 | isa = PBXSourcesBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | 4FA13A491DE1F884009C3448 /* Option.swift in Sources */, 171 | 4FA13A481DE1F884009C3448 /* CommandLine.swift in Sources */, 172 | 4FA13A4A1DE1F884009C3448 /* StringExtensions.swift in Sources */, 173 | 4FA13A4C1DE1FE32009C3448 /* Dictionary.swift in Sources */, 174 | 4FA939C81DE1DEE200D45D48 /* TTTDictionary.m in Sources */, 175 | 4FA939AC1DE1DA0000D45D48 /* main.swift in Sources */, 176 | ); 177 | runOnlyForDeploymentPostprocessing = 0; 178 | }; 179 | /* End PBXSourcesBuildPhase section */ 180 | 181 | /* Begin XCBuildConfiguration section */ 182 | 4FA939AD1DE1DA0000D45D48 /* Debug */ = { 183 | isa = XCBuildConfiguration; 184 | buildSettings = { 185 | ALWAYS_SEARCH_USER_PATHS = NO; 186 | CLANG_ANALYZER_NONNULL = YES; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INT_CONVERSION = YES; 197 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 198 | CLANG_WARN_UNREACHABLE_CODE = YES; 199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 200 | CODE_SIGN_IDENTITY = "-"; 201 | COPY_PHASE_STRIP = NO; 202 | DEBUG_INFORMATION_FORMAT = dwarf; 203 | ENABLE_STRICT_OBJC_MSGSEND = YES; 204 | ENABLE_TESTABILITY = YES; 205 | GCC_C_LANGUAGE_STANDARD = gnu99; 206 | GCC_DYNAMIC_NO_PIC = NO; 207 | GCC_NO_COMMON_BLOCKS = YES; 208 | GCC_OPTIMIZATION_LEVEL = 0; 209 | GCC_PREPROCESSOR_DEFINITIONS = ( 210 | "DEBUG=1", 211 | "$(inherited)", 212 | ); 213 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 214 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 215 | GCC_WARN_UNDECLARED_SELECTOR = YES; 216 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 217 | GCC_WARN_UNUSED_FUNCTION = YES; 218 | GCC_WARN_UNUSED_VARIABLE = YES; 219 | MACOSX_DEPLOYMENT_TARGET = 10.11; 220 | MTL_ENABLE_DEBUG_INFO = YES; 221 | ONLY_ACTIVE_ARCH = YES; 222 | SDKROOT = macosx; 223 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 224 | }; 225 | name = Debug; 226 | }; 227 | 4FA939AE1DE1DA0000D45D48 /* Release */ = { 228 | isa = XCBuildConfiguration; 229 | buildSettings = { 230 | ALWAYS_SEARCH_USER_PATHS = NO; 231 | CLANG_ANALYZER_NONNULL = YES; 232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 233 | CLANG_CXX_LIBRARY = "libc++"; 234 | CLANG_ENABLE_MODULES = YES; 235 | CLANG_ENABLE_OBJC_ARC = YES; 236 | CLANG_WARN_BOOL_CONVERSION = YES; 237 | CLANG_WARN_CONSTANT_CONVERSION = YES; 238 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 239 | CLANG_WARN_EMPTY_BODY = YES; 240 | CLANG_WARN_ENUM_CONVERSION = YES; 241 | CLANG_WARN_INT_CONVERSION = YES; 242 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | CODE_SIGN_IDENTITY = "-"; 246 | COPY_PHASE_STRIP = NO; 247 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 248 | ENABLE_NS_ASSERTIONS = NO; 249 | ENABLE_STRICT_OBJC_MSGSEND = YES; 250 | GCC_C_LANGUAGE_STANDARD = gnu99; 251 | GCC_NO_COMMON_BLOCKS = YES; 252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 254 | GCC_WARN_UNDECLARED_SELECTOR = YES; 255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 256 | GCC_WARN_UNUSED_FUNCTION = YES; 257 | GCC_WARN_UNUSED_VARIABLE = YES; 258 | MACOSX_DEPLOYMENT_TARGET = 10.11; 259 | MTL_ENABLE_DEBUG_INFO = NO; 260 | SDKROOT = macosx; 261 | }; 262 | name = Release; 263 | }; 264 | 4FA939B01DE1DA0000D45D48 /* Debug */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | PRODUCT_NAME = dictionary; 268 | SWIFT_OBJC_BRIDGING_HEADER = "DictionaryOSX/DictionaryOSX-Bridging-Header.h"; 269 | }; 270 | name = Debug; 271 | }; 272 | 4FA939B11DE1DA0000D45D48 /* Release */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | PRODUCT_NAME = dictionary; 276 | SWIFT_OBJC_BRIDGING_HEADER = "DictionaryOSX/DictionaryOSX-Bridging-Header.h"; 277 | }; 278 | name = Release; 279 | }; 280 | /* End XCBuildConfiguration section */ 281 | 282 | /* Begin XCConfigurationList section */ 283 | 4FA939A31DE1DA0000D45D48 /* Build configuration list for PBXProject "DictionaryOSX" */ = { 284 | isa = XCConfigurationList; 285 | buildConfigurations = ( 286 | 4FA939AD1DE1DA0000D45D48 /* Debug */, 287 | 4FA939AE1DE1DA0000D45D48 /* Release */, 288 | ); 289 | defaultConfigurationIsVisible = 0; 290 | defaultConfigurationName = Release; 291 | }; 292 | 4FA939AF1DE1DA0000D45D48 /* Build configuration list for PBXNativeTarget "DictionaryOSX" */ = { 293 | isa = XCConfigurationList; 294 | buildConfigurations = ( 295 | 4FA939B01DE1DA0000D45D48 /* Debug */, 296 | 4FA939B11DE1DA0000D45D48 /* Release */, 297 | ); 298 | defaultConfigurationIsVisible = 0; 299 | defaultConfigurationName = Release; 300 | }; 301 | /* End XCConfigurationList section */ 302 | }; 303 | rootObject = 4FA939A01DE1DA0000D45D48 /* Project object */; 304 | } 305 | -------------------------------------------------------------------------------- /DictionaryOSX.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DictionaryOSX.xcodeproj/xcshareddata/xcschemes/DictionaryOSX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /DictionaryOSX/Dictionary.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class Dictionary { 4 | 5 | func quickFindEntry(term: String) -> TTTDictionaryEntry? { 6 | return findEntry(term, dictionary: DCSOxfordDictionaryOfEnglish) ?? findEntry(term, dictionary: DCSOxfordThesaurusOfEnglish) 7 | } 8 | 9 | func findEntry(term: String, dictionary: String) -> TTTDictionaryEntry? { 10 | let dictionary = TTTDictionary.init(named: dictionary) 11 | let entries = dictionary.entriesForSearchTerm(term) as? [TTTDictionaryEntry] 12 | return entries?.first 13 | } 14 | } 15 | 16 | class DictionaryEntryParser { 17 | 18 | func findSpeechPart(entry: TTTDictionaryEntry) -> String? { 19 | let entryParts = entry.text.characters.split("▶") 20 | guard entryParts.count > 1 else { return nil } 21 | 22 | return entryParts[1].split(" ").first.map({ String($0) }) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /DictionaryOSX/DictionaryOSX-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #ifndef DictionaryOSX_Bridging_Header_h 2 | #define DictionaryOSX_Bridging_Header_h 3 | 4 | #import "TTTDictionary.h" 5 | 6 | #endif -------------------------------------------------------------------------------- /DictionaryOSX/main.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum OutputFormat: String { 4 | case Text = "text" 5 | case HTML = "html" 6 | case SpeechPart = "speech-part" 7 | } 8 | 9 | let cli = CommandLine() 10 | let outputFormatFlag = EnumOption(shortFlag: "f", longFlag: "format", helpMessage: "Output format: [text|html|speech-part]") 11 | let helpFlag = BoolOption(shortFlag: "h", longFlag: "help", helpMessage: "Prints a help message.") 12 | cli.addOptions(outputFormatFlag, helpFlag) 13 | 14 | do { 15 | try cli.parse() 16 | } catch { 17 | cli.printUsage(error) 18 | exit(EX_USAGE) 19 | } 20 | 21 | if helpFlag.wasSet { 22 | cli.printUsage() 23 | exit(0) 24 | } 25 | 26 | guard let term = cli.unparsedArguments.first else { 27 | print("Please include a term to define") 28 | exit(1) 29 | } 30 | 31 | 32 | guard let entry = Dictionary().quickFindEntry(term) else { 33 | exit(1) 34 | } 35 | 36 | switch(outputFormatFlag.value ?? OutputFormat.Text) { 37 | case .HTML: 38 | print(entry.HTML) 39 | 40 | case .SpeechPart: 41 | guard let speechPart = DictionaryEntryParser().findSpeechPart(entry) else { exit(1) } 42 | print(speechPart) 43 | 44 | case .Text: 45 | print(entry.text) 46 | } 47 | 48 | -------------------------------------------------------------------------------- /Frameworks/CommandLine/CommandLine.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * CommandLine.swift 3 | * Copyright (c) 2014 Ben Gollmer. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | import Foundation 19 | /* Required for setlocale(3) */ 20 | #if os(OSX) 21 | import Darwin 22 | #elseif os(Linux) 23 | import Glibc 24 | #endif 25 | 26 | let ShortOptionPrefix = "-" 27 | let LongOptionPrefix = "--" 28 | 29 | /* Stop parsing arguments when an ArgumentStopper (--) is detected. This is a GNU getopt 30 | * convention; cf. https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html 31 | */ 32 | let ArgumentStopper = "--" 33 | 34 | /* Allow arguments to be attached to flags when separated by this character. 35 | * --flag=argument is equivalent to --flag argument 36 | */ 37 | let ArgumentAttacher: Character = "=" 38 | 39 | /* An output stream to stderr; used by CommandLine.printUsage(). */ 40 | #if swift(>=3.0) 41 | private struct StderrOutputStream: OutputStream { 42 | static let stream = StderrOutputStream() 43 | func write(_ s: String) { 44 | fputs(s, stderr) 45 | } 46 | } 47 | #else 48 | private struct StderrOutputStream: OutputStreamType { 49 | static let stream = StderrOutputStream() 50 | func write(s: String) { 51 | fputs(s, stderr) 52 | } 53 | } 54 | #endif 55 | 56 | /** 57 | * The CommandLine class implements a command-line interface for your app. 58 | * 59 | * To use it, define one or more Options (see Option.swift) and add them to your 60 | * CommandLine object, then invoke `parse()`. Each Option object will be populated with 61 | * the value given by the user. 62 | * 63 | * If any required options are missing or if an invalid value is found, `parse()` will throw 64 | * a `ParseError`. You can then call `printUsage()` to output an automatically-generated usage 65 | * message. 66 | */ 67 | public class CommandLine { 68 | private var _arguments: [String] 69 | private var _options: [Option] = [Option]() 70 | private var _maxFlagDescriptionWidth: Int = 0 71 | private var _usedFlags: Set { 72 | var usedFlags = Set(minimumCapacity: _options.count * 2) 73 | 74 | for option in _options { 75 | for case let flag? in [option.shortFlag, option.longFlag] { 76 | usedFlags.insert(flag) 77 | } 78 | } 79 | 80 | return usedFlags 81 | } 82 | 83 | /** 84 | * After calling `parse()`, this property will contain any values that weren't captured 85 | * by an Option. For example: 86 | * 87 | * ``` 88 | * let cli = CommandLine() 89 | * let fileType = StringOption(shortFlag: "t", longFlag: "type", required: true, helpMessage: "Type of file") 90 | * 91 | * do { 92 | * try cli.parse() 93 | * print("File type is \(type), files are \(cli.unparsedArguments)") 94 | * catch { 95 | * cli.printUsage(error) 96 | * exit(EX_USAGE) 97 | * } 98 | * 99 | * --- 100 | * 101 | * $ ./readfiles --type=pdf ~/file1.pdf ~/file2.pdf 102 | * File type is pdf, files are ["~/file1.pdf", "~/file2.pdf"] 103 | * ``` 104 | */ 105 | public private(set) var unparsedArguments: [String] = [String]() 106 | 107 | /** 108 | * If supplied, this function will be called when printing usage messages. 109 | * 110 | * You can use the `defaultFormat` function to get the normally-formatted 111 | * output, either before or after modifying the provided string. For example: 112 | * 113 | * ``` 114 | * let cli = CommandLine() 115 | * cli.formatOutput = { str, type in 116 | * switch(type) { 117 | * case .Error: 118 | * // Make errors shouty 119 | * return defaultFormat(str.uppercaseString, type: type) 120 | * case .OptionHelp: 121 | * // Don't use the default indenting 122 | * return ">> \(s)\n" 123 | * default: 124 | * return defaultFormat(str, type: type) 125 | * } 126 | * } 127 | * ``` 128 | * 129 | * - note: Newlines are not appended to the result of this function. If you don't use 130 | * `defaultFormat()`, be sure to add them before returning. 131 | */ 132 | public var formatOutput: ((String, OutputType) -> String)? 133 | 134 | /** 135 | * The maximum width of all options' `flagDescription` properties; provided for use by 136 | * output formatters. 137 | * 138 | * - seealso: `defaultFormat`, `formatOutput` 139 | */ 140 | public var maxFlagDescriptionWidth: Int { 141 | if _maxFlagDescriptionWidth == 0 { 142 | #if swift(>=3.0) 143 | _maxFlagDescriptionWidth = _options.map { $0.flagDescription.characters.count }.sorted().first ?? 0 144 | #else 145 | _maxFlagDescriptionWidth = _options.map { $0.flagDescription.characters.count }.sort().first ?? 0 146 | #endif 147 | } 148 | 149 | return _maxFlagDescriptionWidth 150 | } 151 | 152 | /** 153 | * The type of output being supplied to an output formatter. 154 | * 155 | * - seealso: `formatOutput` 156 | */ 157 | public enum OutputType { 158 | /** About text: `Usage: command-example [options]` and the like */ 159 | case About 160 | 161 | /** An error message: `Missing required option --extract` */ 162 | case Error 163 | 164 | /** An Option's `flagDescription`: `-h, --help:` */ 165 | case OptionFlag 166 | 167 | /** An Option's help message */ 168 | case OptionHelp 169 | } 170 | 171 | /** A ParseError is thrown if the `parse()` method fails. */ 172 | #if swift(>=3.0) 173 | public enum ParseError: ErrorProtocol, CustomStringConvertible { 174 | /** Thrown if an unrecognized argument is passed to `parse()` in strict mode */ 175 | case InvalidArgument(String) 176 | 177 | /** Thrown if the value for an Option is invalid (e.g. a string is passed to an IntOption) */ 178 | case InvalidValueForOption(Option, [String]) 179 | 180 | /** Thrown if an Option with required: true is missing */ 181 | case MissingRequiredOptions([Option]) 182 | 183 | public var description: String { 184 | switch self { 185 | case let .InvalidArgument(arg): 186 | return "Invalid argument: \(arg)" 187 | case let .InvalidValueForOption(opt, vals): 188 | let vs = vals.joined(separator: ", ") 189 | return "Invalid value(s) for option \(opt.flagDescription): \(vs)" 190 | case let .MissingRequiredOptions(opts): 191 | return "Missing required options: \(opts.map { return $0.flagDescription })" 192 | } 193 | } 194 | } 195 | #else 196 | public enum ParseError: ErrorType, CustomStringConvertible { 197 | /** Thrown if an unrecognized argument is passed to `parse()` in strict mode */ 198 | case InvalidArgument(String) 199 | 200 | /** Thrown if the value for an Option is invalid (e.g. a string is passed to an IntOption) */ 201 | case InvalidValueForOption(Option, [String]) 202 | 203 | /** Thrown if an Option with required: true is missing */ 204 | case MissingRequiredOptions([Option]) 205 | 206 | public var description: String { 207 | switch self { 208 | case let .InvalidArgument(arg): 209 | return "Invalid argument: \(arg)" 210 | case let .InvalidValueForOption(opt, vals): 211 | let vs = vals.joinWithSeparator(", ") 212 | return "Invalid value(s) for option \(opt.flagDescription): \(vs)" 213 | case let .MissingRequiredOptions(opts): 214 | return "Missing required options: \(opts.map { return $0.flagDescription })" 215 | } 216 | } 217 | } 218 | #endif 219 | 220 | /** 221 | * Initializes a CommandLine object. 222 | * 223 | * - parameter arguments: Arguments to parse. If omitted, the arguments passed to the app 224 | * on the command line will automatically be used. 225 | * 226 | * - returns: An initalized CommandLine object. 227 | */ 228 | public init(arguments: [String] = Process.arguments) { 229 | self._arguments = arguments 230 | 231 | /* Initialize locale settings from the environment */ 232 | setlocale(LC_ALL, "") 233 | } 234 | 235 | #if swift(>=3.0) 236 | 237 | /* Returns all argument values from flagIndex to the next flag or the end of the argument array. */ 238 | private func _getFlagValues(_ flagIndex: Int, _ attachedArg: String? = nil) -> [String] { 239 | var args: [String] = [String]() 240 | var skipFlagChecks = false 241 | 242 | if let a = attachedArg { 243 | args.append(a) 244 | } 245 | 246 | for i in flagIndex + 1 ..< _arguments.count { 247 | if !skipFlagChecks { 248 | if _arguments[i] == ArgumentStopper { 249 | skipFlagChecks = true 250 | continue 251 | } 252 | 253 | if _arguments[i].hasPrefix(ShortOptionPrefix) && Int(_arguments[i]) == nil && 254 | _arguments[i].toDouble() == nil { 255 | break 256 | } 257 | } 258 | 259 | args.append(_arguments[i]) 260 | } 261 | 262 | return args 263 | } 264 | 265 | /** 266 | * Adds an Option to the command line. 267 | * 268 | * - parameter option: The option to add. 269 | */ 270 | public func addOption(_ option: Option) { 271 | let uf = _usedFlags 272 | for case let flag? in [option.shortFlag, option.longFlag] { 273 | assert(!uf.contains(flag), "Flag '\(flag)' already in use") 274 | } 275 | 276 | _options.append(option) 277 | _maxFlagDescriptionWidth = 0 278 | } 279 | 280 | /** 281 | * Adds one or more Options to the command line. 282 | * 283 | * - parameter options: An array containing the options to add. 284 | */ 285 | public func addOptions(_ options: [Option]) { 286 | for o in options { 287 | addOption(o) 288 | } 289 | } 290 | 291 | /** 292 | * Adds one or more Options to the command line. 293 | * 294 | * - parameter options: The options to add. 295 | */ 296 | public func addOptions(_ options: Option...) { 297 | for o in options { 298 | addOption(o) 299 | } 300 | } 301 | 302 | /** 303 | * Sets the command line Options. Any existing options will be overwritten. 304 | * 305 | * - parameter options: An array containing the options to set. 306 | */ 307 | public func setOptions(_ options: [Option]) { 308 | _options = [Option]() 309 | addOptions(options) 310 | } 311 | 312 | /** 313 | * Sets the command line Options. Any existing options will be overwritten. 314 | * 315 | * - parameter options: The options to set. 316 | */ 317 | public func setOptions(_ options: Option...) { 318 | _options = [Option]() 319 | addOptions(options) 320 | } 321 | 322 | #else 323 | 324 | /* Returns all argument values from flagIndex to the next flag or the end of the argument array. */ 325 | private func _getFlagValues(flagIndex: Int, _ attachedArg: String? = nil) -> [String] { 326 | var args: [String] = [String]() 327 | var skipFlagChecks = false 328 | 329 | if let a = attachedArg { 330 | args.append(a) 331 | } 332 | 333 | for i in flagIndex + 1 ..< _arguments.count { 334 | if !skipFlagChecks { 335 | if _arguments[i] == ArgumentStopper { 336 | skipFlagChecks = true 337 | continue 338 | } 339 | 340 | if _arguments[i].hasPrefix(ShortOptionPrefix) && Int(_arguments[i]) == nil && 341 | _arguments[i].toDouble() == nil { 342 | break 343 | } 344 | } 345 | 346 | args.append(_arguments[i]) 347 | } 348 | 349 | return args 350 | } 351 | 352 | /** 353 | * Adds an Option to the command line. 354 | * 355 | * - parameter option: The option to add. 356 | */ 357 | public func addOption(option: Option) { 358 | let uf = _usedFlags 359 | for case let flag? in [option.shortFlag, option.longFlag] { 360 | assert(!uf.contains(flag), "Flag '\(flag)' already in use") 361 | } 362 | 363 | _options.append(option) 364 | _maxFlagDescriptionWidth = 0 365 | } 366 | 367 | /** 368 | * Adds one or more Options to the command line. 369 | * 370 | * - parameter options: An array containing the options to add. 371 | */ 372 | public func addOptions(options: [Option]) { 373 | for o in options { 374 | addOption(o) 375 | } 376 | } 377 | 378 | /** 379 | * Adds one or more Options to the command line. 380 | * 381 | * - parameter options: The options to add. 382 | */ 383 | public func addOptions(options: Option...) { 384 | for o in options { 385 | addOption(o) 386 | } 387 | } 388 | 389 | /** 390 | * Sets the command line Options. Any existing options will be overwritten. 391 | * 392 | * - parameter options: An array containing the options to set. 393 | */ 394 | public func setOptions(options: [Option]) { 395 | _options = [Option]() 396 | addOptions(options) 397 | } 398 | 399 | /** 400 | * Sets the command line Options. Any existing options will be overwritten. 401 | * 402 | * - parameter options: The options to set. 403 | */ 404 | public func setOptions(options: Option...) { 405 | _options = [Option]() 406 | addOptions(options) 407 | } 408 | 409 | #endif 410 | 411 | /** 412 | * Parses command-line arguments into their matching Option values. 413 | * 414 | * - parameter strict: Fail if any unrecognized flags are present (default: false). 415 | * 416 | * - throws: A `ParseError` if argument parsing fails: 417 | * - `.InvalidArgument` if an unrecognized flag is present and `strict` is true 418 | * - `.InvalidValueForOption` if the value supplied to an option is not valid (for 419 | * example, a string is supplied for an IntOption) 420 | * - `.MissingRequiredOptions` if a required option isn't present 421 | */ 422 | public func parse(strict: Bool = false) throws { 423 | var strays = _arguments 424 | 425 | /* Nuke executable name */ 426 | strays[0] = "" 427 | 428 | #if swift(>=3.0) 429 | let argumentsEnumerator = _arguments.enumerated() 430 | #else 431 | let argumentsEnumerator = _arguments.enumerate() 432 | #endif 433 | for (idx, arg) in argumentsEnumerator { 434 | if arg == ArgumentStopper { 435 | break 436 | } 437 | 438 | if !arg.hasPrefix(ShortOptionPrefix) { 439 | continue 440 | } 441 | 442 | let skipChars = arg.hasPrefix(LongOptionPrefix) ? 443 | LongOptionPrefix.characters.count : ShortOptionPrefix.characters.count 444 | #if swift(>=3.0) 445 | let flagWithArg = arg[arg.index(arg.startIndex, offsetBy: skipChars)..=3.0) 481 | let flagCharactersEnumerator = flag.characters.enumerated() 482 | #else 483 | let flagCharactersEnumerator = flag.characters.enumerate() 484 | #endif 485 | for (i, c) in flagCharactersEnumerator { 486 | for option in _options where option.flagMatch(String(c)) { 487 | /* Values are allowed at the end of the concatenated flags, e.g. 488 | * -xvf 489 | */ 490 | let vals = (i == flagLength - 1) ? self._getFlagValues(idx, attachedArg) : [String]() 491 | guard option.setValue(vals) else { 492 | throw ParseError.InvalidValueForOption(option, vals) 493 | } 494 | 495 | var claimedIdx = idx + option.claimedValues 496 | if attachedArg != nil { claimedIdx -= 1 } 497 | for i in idx...claimedIdx { 498 | strays[i] = "" 499 | } 500 | 501 | flagMatched = true 502 | break 503 | } 504 | } 505 | } 506 | 507 | /* Invalid flag */ 508 | guard !strict || flagMatched else { 509 | throw ParseError.InvalidArgument(arg) 510 | } 511 | } 512 | 513 | /* Check to see if any required options were not matched */ 514 | let missingOptions = _options.filter { $0.required && !$0.wasSet } 515 | guard missingOptions.count == 0 else { 516 | throw ParseError.MissingRequiredOptions(missingOptions) 517 | } 518 | 519 | unparsedArguments = strays.filter { $0 != "" } 520 | } 521 | 522 | /** 523 | * Provides the default formatting of `printUsage()` output. 524 | * 525 | * - parameter s: The string to format. 526 | * - parameter type: Type of output. 527 | * 528 | * - returns: The formatted string. 529 | * - seealso: `formatOutput` 530 | */ 531 | public func defaultFormat(s: String, type: OutputType) -> String { 532 | switch type { 533 | case .About: 534 | return "\(s)\n" 535 | case .Error: 536 | return "\(s)\n\n" 537 | case .OptionFlag: 538 | return " \(s.padded(toWidth: maxFlagDescriptionWidth)):\n" 539 | case .OptionHelp: 540 | return " \(s)\n" 541 | } 542 | } 543 | 544 | /* printUsage() is generic for OutputStreamType because the Swift compiler crashes 545 | * on inout protocol function parameters in Xcode 7 beta 1 (rdar://21372694). 546 | */ 547 | 548 | /** 549 | * Prints a usage message. 550 | * 551 | * - parameter to: An OutputStreamType to write the error message to. 552 | */ 553 | #if swift(>=3.0) 554 | public func printUsage(_ to: inout TargetStream) { 555 | /* Nil coalescing operator (??) doesn't work on closures :( */ 556 | let format = formatOutput != nil ? formatOutput! : defaultFormat 557 | 558 | let name = _arguments[0] 559 | print(format("Usage: \(name) [options]", .About), terminator: "", to: &to) 560 | 561 | for opt in _options { 562 | print(format(opt.flagDescription, .OptionFlag), terminator: "", to: &to) 563 | print(format(opt.helpMessage, .OptionHelp), terminator: "", to: &to) 564 | } 565 | } 566 | #else 567 | public func printUsage(inout to: TargetStream) { 568 | /* Nil coalescing operator (??) doesn't work on closures :( */ 569 | let format = formatOutput != nil ? formatOutput! : defaultFormat 570 | 571 | let name = _arguments[0] 572 | print(format("Usage: \(name) [options]", .About), terminator: "", toStream: &to) 573 | 574 | for opt in _options { 575 | print(format(opt.flagDescription, .OptionFlag), terminator: "", toStream: &to) 576 | print(format(opt.helpMessage, .OptionHelp), terminator: "", toStream: &to) 577 | } 578 | } 579 | #endif 580 | 581 | /** 582 | * Prints a usage message. 583 | * 584 | * - parameter error: An error thrown from `parse()`. A description of the error 585 | * (e.g. "Missing required option --extract") will be printed before the usage message. 586 | * - parameter to: An OutputStreamType to write the error message to. 587 | */ 588 | #if swift(>=3.0) 589 | public func printUsage(_ error: ErrorProtocol, to: inout TargetStream) { 590 | let format = formatOutput != nil ? formatOutput! : defaultFormat 591 | print(format("\(error)", .Error), terminator: "", to: &to) 592 | printUsage(&to) 593 | } 594 | #else 595 | public func printUsage(error: ErrorType, inout to: TargetStream) { 596 | let format = formatOutput != nil ? formatOutput! : defaultFormat 597 | print(format("\(error)", .Error), terminator: "", toStream: &to) 598 | printUsage(&to) 599 | } 600 | #endif 601 | 602 | /** 603 | * Prints a usage message. 604 | * 605 | * - parameter error: An error thrown from `parse()`. A description of the error 606 | * (e.g. "Missing required option --extract") will be printed before the usage message. 607 | */ 608 | #if swift(>=3.0) 609 | public func printUsage(_ error: ErrorProtocol) { 610 | var out = StderrOutputStream.stream 611 | printUsage(error, to: &out) 612 | } 613 | #else 614 | public func printUsage(error: ErrorType) { 615 | var out = StderrOutputStream.stream 616 | printUsage(error, to: &out) 617 | } 618 | #endif 619 | 620 | /** 621 | * Prints a usage message. 622 | */ 623 | public func printUsage() { 624 | var out = StderrOutputStream.stream 625 | printUsage(&out) 626 | } 627 | } 628 | -------------------------------------------------------------------------------- /Frameworks/CommandLine/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSHumanReadableCopyright 24 | Copyright © 2014 Ben Gollmer. Licensed under the Apache License, Version 2.0. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Frameworks/CommandLine/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Frameworks/CommandLine/Option.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Option.swift 3 | * Copyright (c) 2014 Ben Gollmer. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * The base class for a command-line option. 20 | */ 21 | public class Option { 22 | public let shortFlag: String? 23 | public let longFlag: String? 24 | public let required: Bool 25 | public let helpMessage: String 26 | 27 | /** True if the option was set when parsing command-line arguments */ 28 | public var wasSet: Bool { 29 | return false 30 | } 31 | 32 | public var claimedValues: Int { return 0 } 33 | 34 | public var flagDescription: String { 35 | switch (shortFlag, longFlag) { 36 | case let (sf?, lf?): 37 | return "\(ShortOptionPrefix)\(sf), \(LongOptionPrefix)\(lf)" 38 | case (nil, let lf?): 39 | return "\(LongOptionPrefix)\(lf)" 40 | case (let sf?, nil): 41 | return "\(ShortOptionPrefix)\(sf)" 42 | default: 43 | return "" 44 | } 45 | } 46 | 47 | private init(_ shortFlag: String?, _ longFlag: String?, _ required: Bool, _ helpMessage: String) { 48 | if let sf = shortFlag { 49 | assert(sf.characters.count == 1, "Short flag must be a single character") 50 | assert(Int(sf) == nil && sf.toDouble() == nil, "Short flag cannot be a numeric value") 51 | } 52 | 53 | if let lf = longFlag { 54 | assert(Int(lf) == nil && lf.toDouble() == nil, "Long flag cannot be a numeric value") 55 | } 56 | 57 | self.shortFlag = shortFlag 58 | self.longFlag = longFlag 59 | self.helpMessage = helpMessage 60 | self.required = required 61 | } 62 | 63 | /* The optional casts in these initalizers force them to call the private initializer. Without 64 | * the casts, they recursively call themselves. 65 | */ 66 | 67 | /** Initializes a new Option that has both long and short flags. */ 68 | public convenience init(shortFlag: String, longFlag: String, required: Bool = false, helpMessage: String) { 69 | self.init(shortFlag as String?, longFlag, required, helpMessage) 70 | } 71 | 72 | /** Initializes a new Option that has only a short flag. */ 73 | public convenience init(shortFlag: String, required: Bool = false, helpMessage: String) { 74 | self.init(shortFlag as String?, nil, required, helpMessage) 75 | } 76 | 77 | /** Initializes a new Option that has only a long flag. */ 78 | public convenience init(longFlag: String, required: Bool = false, helpMessage: String) { 79 | self.init(nil, longFlag as String?, required, helpMessage) 80 | } 81 | 82 | #if swift(>=3.0) 83 | func flagMatch(_ flag: String) -> Bool { 84 | return flag == shortFlag || flag == longFlag 85 | } 86 | 87 | func setValue(_ values: [String]) -> Bool { 88 | return false 89 | } 90 | #else 91 | func flagMatch(flag: String) -> Bool { 92 | return flag == shortFlag || flag == longFlag 93 | } 94 | 95 | func setValue(values: [String]) -> Bool { 96 | return false 97 | } 98 | #endif 99 | } 100 | 101 | /** 102 | * A boolean option. The presence of either the short or long flag will set the value to true; 103 | * absence of the flag(s) is equivalent to false. 104 | */ 105 | public class BoolOption: Option { 106 | private var _value: Bool = false 107 | 108 | public var value: Bool { 109 | return _value 110 | } 111 | 112 | override public var wasSet: Bool { 113 | return _value 114 | } 115 | 116 | #if swift(>=3.0) 117 | override func setValue(_ values: [String]) -> Bool { 118 | _value = true 119 | return true 120 | } 121 | #else 122 | override func setValue(values: [String]) -> Bool { 123 | _value = true 124 | return true 125 | } 126 | #endif 127 | } 128 | 129 | /** An option that accepts a positive or negative integer value. */ 130 | public class IntOption: Option { 131 | private var _value: Int? 132 | 133 | public var value: Int? { 134 | return _value 135 | } 136 | 137 | override public var wasSet: Bool { 138 | return _value != nil 139 | } 140 | 141 | override public var claimedValues: Int { 142 | return _value != nil ? 1 : 0 143 | } 144 | 145 | #if swift(>=3.0) 146 | override func setValue(_ values: [String]) -> Bool { 147 | if values.count == 0 { 148 | return false 149 | } 150 | 151 | if let val = Int(values[0]) { 152 | _value = val 153 | return true 154 | } 155 | 156 | return false 157 | } 158 | #else 159 | override func setValue(values: [String]) -> Bool { 160 | if values.count == 0 { 161 | return false 162 | } 163 | 164 | if let val = Int(values[0]) { 165 | _value = val 166 | return true 167 | } 168 | 169 | return false 170 | } 171 | #endif 172 | } 173 | 174 | /** 175 | * An option that represents an integer counter. Each time the short or long flag is found 176 | * on the command-line, the counter will be incremented. 177 | */ 178 | public class CounterOption: Option { 179 | private var _value: Int = 0 180 | 181 | public var value: Int { 182 | return _value 183 | } 184 | 185 | override public var wasSet: Bool { 186 | return _value > 0 187 | } 188 | 189 | public func reset() { 190 | _value = 0 191 | } 192 | 193 | #if swift(>=3.0) 194 | override func setValue(_ values: [String]) -> Bool { 195 | _value += 1 196 | return true 197 | } 198 | #else 199 | override func setValue(values: [String]) -> Bool { 200 | _value += 1 201 | return true 202 | } 203 | #endif 204 | } 205 | 206 | /** An option that accepts a positive or negative floating-point value. */ 207 | public class DoubleOption: Option { 208 | private var _value: Double? 209 | 210 | public var value: Double? { 211 | return _value 212 | } 213 | 214 | override public var wasSet: Bool { 215 | return _value != nil 216 | } 217 | 218 | override public var claimedValues: Int { 219 | return _value != nil ? 1 : 0 220 | } 221 | 222 | #if swift(>=3.0) 223 | 224 | override func setValue(_ values: [String]) -> Bool { 225 | if values.count == 0 { 226 | return false 227 | } 228 | 229 | if let val = values[0].toDouble() { 230 | _value = val 231 | return true 232 | } 233 | 234 | return false 235 | } 236 | 237 | #else 238 | 239 | override func setValue(values: [String]) -> Bool { 240 | if values.count == 0 { 241 | return false 242 | } 243 | 244 | if let val = values[0].toDouble() { 245 | _value = val 246 | return true 247 | } 248 | 249 | return false 250 | } 251 | 252 | #endif 253 | } 254 | 255 | /** An option that accepts a string value. */ 256 | public class StringOption: Option { 257 | private var _value: String? = nil 258 | 259 | public var value: String? { 260 | return _value 261 | } 262 | 263 | override public var wasSet: Bool { 264 | return _value != nil 265 | } 266 | 267 | override public var claimedValues: Int { 268 | return _value != nil ? 1 : 0 269 | } 270 | 271 | #if swift(>=3.0) 272 | 273 | override func setValue(_ values: [String]) -> Bool { 274 | if values.count == 0 { 275 | return false 276 | } 277 | 278 | _value = values[0] 279 | return true 280 | } 281 | 282 | #else 283 | 284 | override func setValue(values: [String]) -> Bool { 285 | if values.count == 0 { 286 | return false 287 | } 288 | 289 | _value = values[0] 290 | return true 291 | } 292 | 293 | #endif 294 | } 295 | 296 | /** An option that accepts one or more string values. */ 297 | public class MultiStringOption: Option { 298 | private var _value: [String]? 299 | 300 | public var value: [String]? { 301 | return _value 302 | } 303 | 304 | override public var wasSet: Bool { 305 | return _value != nil 306 | } 307 | 308 | override public var claimedValues: Int { 309 | if let v = _value { 310 | return v.count 311 | } 312 | 313 | return 0 314 | } 315 | 316 | #if swift(>=3.0) 317 | 318 | override func setValue(_ values: [String]) -> Bool { 319 | if values.count == 0 { 320 | return false 321 | } 322 | 323 | _value = values 324 | return true 325 | } 326 | 327 | #else 328 | 329 | override func setValue(values: [String]) -> Bool { 330 | if values.count == 0 { 331 | return false 332 | } 333 | 334 | _value = values 335 | return true 336 | } 337 | 338 | #endif 339 | } 340 | 341 | /** An option that represents an enum value. */ 342 | public class EnumOption: Option { 343 | private var _value: T? 344 | public var value: T? { 345 | return _value 346 | } 347 | 348 | override public var wasSet: Bool { 349 | return _value != nil 350 | } 351 | 352 | override public var claimedValues: Int { 353 | return _value != nil ? 1 : 0 354 | } 355 | 356 | /* Re-defining the intializers is necessary to make the Swift 2 compiler happy, as 357 | * of Xcode 7 beta 2. 358 | */ 359 | 360 | private override init(_ shortFlag: String?, _ longFlag: String?, _ required: Bool, _ helpMessage: String) { 361 | super.init(shortFlag, longFlag, required, helpMessage) 362 | } 363 | 364 | /** Initializes a new Option that has both long and short flags. */ 365 | public convenience init(shortFlag: String, longFlag: String, required: Bool = false, helpMessage: String) { 366 | self.init(shortFlag as String?, longFlag, required, helpMessage) 367 | } 368 | 369 | /** Initializes a new Option that has only a short flag. */ 370 | public convenience init(shortFlag: String, required: Bool = false, helpMessage: String) { 371 | self.init(shortFlag as String?, nil, required, helpMessage) 372 | } 373 | 374 | /** Initializes a new Option that has only a long flag. */ 375 | public convenience init(longFlag: String, required: Bool = false, helpMessage: String) { 376 | self.init(nil, longFlag as String?, required, helpMessage) 377 | } 378 | 379 | #if swift(>=3.0) 380 | 381 | override func setValue(_ values: [String]) -> Bool { 382 | if values.count == 0 { 383 | return false 384 | } 385 | 386 | if let v = T(rawValue: values[0]) { 387 | _value = v 388 | return true 389 | } 390 | 391 | return false 392 | } 393 | 394 | #else 395 | 396 | override func setValue(values: [String]) -> Bool { 397 | if values.count == 0 { 398 | return false 399 | } 400 | 401 | if let v = T(rawValue: values[0]) { 402 | _value = v 403 | return true 404 | } 405 | 406 | return false 407 | } 408 | 409 | #endif 410 | } 411 | -------------------------------------------------------------------------------- /Frameworks/CommandLine/StringExtensions.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * StringExtensions.swift 3 | * Copyright (c) 2014 Ben Gollmer. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /* Required for localeconv(3) */ 19 | #if os(OSX) 20 | import Darwin 21 | #elseif os(Linux) 22 | import Glibc 23 | #endif 24 | 25 | internal extension String { 26 | /* Retrieves locale-specified decimal separator from the environment 27 | * using localeconv(3). 28 | */ 29 | private func _localDecimalPoint() -> Character { 30 | let locale = localeconv() 31 | if locale != nil { 32 | #if swift(>=3.0) 33 | if let decimalPoint = locale?.pointee.decimal_point { 34 | return Character(UnicodeScalar(UInt32(decimalPoint.pointee))) 35 | } 36 | #else 37 | let decimalPoint = locale.memory.decimal_point 38 | if decimalPoint != nil { 39 | return Character(UnicodeScalar(UInt32(decimalPoint.memory))) 40 | } 41 | #endif 42 | } 43 | 44 | return "." 45 | } 46 | 47 | /** 48 | * Attempts to parse the string value into a Double. 49 | * 50 | * - returns: A Double if the string can be parsed, nil otherwise. 51 | */ 52 | func toDouble() -> Double? { 53 | var characteristic: String = "0" 54 | var mantissa: String = "0" 55 | var inMantissa: Bool = false 56 | var isNegative: Bool = false 57 | let decimalPoint = self._localDecimalPoint() 58 | 59 | #if swift(>=3.0) 60 | let charactersEnumerator = self.characters.enumerated() 61 | #else 62 | let charactersEnumerator = self.characters.enumerate() 63 | #endif 64 | for (i, c) in charactersEnumerator { 65 | if i == 0 && c == "-" { 66 | isNegative = true 67 | continue 68 | } 69 | 70 | if c == decimalPoint { 71 | inMantissa = true 72 | continue 73 | } 74 | 75 | if Int(String(c)) != nil { 76 | if !inMantissa { 77 | characteristic.append(c) 78 | } else { 79 | mantissa.append(c) 80 | } 81 | } else { 82 | /* Non-numeric character found, bail */ 83 | return nil 84 | } 85 | } 86 | 87 | return (Double(Int(characteristic)!) + 88 | Double(Int(mantissa)!) / pow(Double(10), Double(mantissa.characters.count - 1))) * 89 | (isNegative ? -1 : 1) 90 | } 91 | 92 | #if swift(>=3.0) 93 | /** 94 | * Splits a string into an array of string components. 95 | * 96 | * - parameter by: The character to split on. 97 | * - parameter maxSplits: The maximum number of splits to perform. If 0, all possible splits are made. 98 | * 99 | * - returns: An array of string components. 100 | */ 101 | func split(by: Character, maxSplits: Int = 0) -> [String] { 102 | var s = [String]() 103 | var numSplits = 0 104 | 105 | var curIdx = self.startIndex 106 | for i in self.characters.indices { 107 | let c = self[i] 108 | if c == by && (maxSplits == 0 || numSplits < maxSplits) { 109 | s.append(self[curIdx.. [String] { 133 | var s = [String]() 134 | var numSplits = 0 135 | 136 | var curIdx = self.startIndex 137 | for i in self.characters.indices { 138 | let c = self[i] 139 | if c == by && (maxSplits == 0 || numSplits < maxSplits) { 140 | s.append(self[curIdx.. String { 164 | var s = self 165 | var currentLength = self.characters.count 166 | 167 | while currentLength < width { 168 | s.append(padChar) 169 | currentLength += 1 170 | } 171 | 172 | return s 173 | } 174 | 175 | /** 176 | * Wraps a string to the specified width. 177 | * 178 | * This just does simple greedy word-packing, it doesn't go full Knuth-Plass. 179 | * If a single word is longer than the line width, it will be placed (unsplit) 180 | * on a line by itself. 181 | * 182 | * - parameter atWidth: The maximum length of a line. 183 | * - parameter wrapBy: The line break character to use. 184 | * - parameter splitBy: The character to use when splitting the string into words. 185 | * 186 | * - returns: A new string, wrapped at the given width. 187 | */ 188 | func wrapped(atWidth width: Int, wrapBy: Character = "\n", splitBy: Character = " ") -> String { 189 | var s = "" 190 | var currentLineWidth = 0 191 | 192 | for word in self.split(by: splitBy) { 193 | let wordLength = word.characters.count 194 | 195 | if currentLineWidth + wordLength + 1 > width { 196 | /* Word length is greater than line length, can't wrap */ 197 | if wordLength >= width { 198 | s += word 199 | } 200 | 201 | s.append(wrapBy) 202 | currentLineWidth = 0 203 | } 204 | 205 | currentLineWidth += wordLength + 1 206 | s += word 207 | s.append(splitBy) 208 | } 209 | 210 | return s 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/DictionaryKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 9 | 10 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/DictionaryKit/DictionaryKit.h: -------------------------------------------------------------------------------- 1 | // DictionaryKit.h 2 | // 3 | // Copyright (c) 2014 Mattt Thompson 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #ifndef _DICTIONARY_KIT_ 24 | #define _DICTIONARY_KIT_ 25 | 26 | #import "TTTDictionary.h" 27 | #endif 28 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/DictionaryKit/TTTDictionary.h: -------------------------------------------------------------------------------- 1 | // TTTDictionary.h 2 | // 3 | // Copyright (c) 2014 Mattt Thompson 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | /** 26 | 27 | */ 28 | @interface TTTDictionaryEntry : NSObject 29 | 30 | /** 31 | 32 | */ 33 | @property (readonly, nonatomic, copy) NSString *headword; 34 | 35 | /** 36 | 37 | */ 38 | @property (readonly, nonatomic, copy) NSString *text; 39 | 40 | /** 41 | 42 | */ 43 | @property (readonly, nonatomic, copy) NSString *HTML; 44 | 45 | @end 46 | 47 | #pragma mark - 48 | 49 | /** 50 | 51 | */ 52 | @interface TTTDictionary : NSObject 53 | 54 | /** 55 | 56 | */ 57 | @property (readonly, nonatomic, copy) NSString *name; 58 | 59 | /** 60 | 61 | */ 62 | @property (readonly, nonatomic, copy) NSString *shortName; 63 | 64 | /** 65 | 66 | */ 67 | + (NSSet *)availableDictionaries; 68 | 69 | /** 70 | 71 | */ 72 | + (instancetype)dictionaryNamed:(NSString *)name; 73 | 74 | /** 75 | 76 | */ 77 | - (NSArray *)entriesForSearchTerm:(NSString *)term; 78 | 79 | @end 80 | 81 | /// @name Constants 82 | 83 | extern NSString * const DCSAppleDictionaryName; 84 | extern NSString * const DCSDutchDictionaryName; 85 | extern NSString * const DCSFrenchDictionaryName; 86 | extern NSString * const DCSGermanDictionaryName; 87 | extern NSString * const DCSItalianDictionaryName; 88 | extern NSString * const DCSJapaneseDictionaryName; 89 | extern NSString * const DCSJapaneseSupaDaijirinDictionaryName; 90 | extern NSString * const DCSJapanese_EnglishDictionaryName; 91 | extern NSString * const DCSKoreanDictionaryName; 92 | extern NSString * const DCSKorean_EnglishDictionaryName; 93 | extern NSString * const DCSNewOxfordAmericanDictionaryName; 94 | extern NSString * const DCSOxfordAmericanWritersThesaurus; 95 | extern NSString * const DCSOxfordDictionaryOfEnglish; 96 | extern NSString * const DCSOxfordThesaurusOfEnglish; 97 | extern NSString * const DCSSimplifiedChineseDictionaryName; 98 | extern NSString * const DCSSimplifiedChinese_EnglishDictionaryName; 99 | extern NSString * const DCSSpanishDictionaryName; 100 | extern NSString * const DCSWikipediaDictionaryName; 101 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/DictionaryKit/TTTDictionary.m: -------------------------------------------------------------------------------- 1 | // TTTDictionary.m 2 | // 3 | // Copyright (c) 2014 Mattt Thompson 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import "TTTDictionary.h" 24 | 25 | #import 26 | 27 | NSString * const DCSAppleDictionaryName = @"Apple Dictionary"; 28 | NSString * const DCSDutchDictionaryName = @"Prisma woordenboek Nederlands"; 29 | NSString * const DCSFrenchDictionaryName = @"Multidictionnaire de la langue française"; 30 | NSString * const DCSGermanDictionaryName = @"Duden-Wissensnetz deutsche Sprache"; 31 | NSString * const DCSItalianDictionaryName = @"Dizionario italiano da un affiliato di Oxford University Press"; 32 | NSString * const DCSJapaneseSupaDaijirinDictionaryName = @"スーパー大辞林"; 33 | NSString * const DCSJapanese_EnglishDictionaryName = @"ウィズダム英和辞典 / ウィズダム和英辞典"; 34 | NSString * const DCSKoreanDictionaryName = @"New Ace Korean Language Dictionary"; 35 | NSString * const DCSKorean_EnglishDictionaryName = @"New Ace English-Korean Dictionary and New Ace Korean-English Dictionary"; 36 | NSString * const DCSNewOxfordAmericanDictionaryName = @"New Oxford American Dictionary"; 37 | NSString * const DCSOxfordAmericanWritersThesaurus = @"Oxford American Writer's Thesaurus"; 38 | NSString * const DCSOxfordDictionaryOfEnglish = @"Oxford Dictionary of English"; 39 | NSString * const DCSOxfordThesaurusOfEnglish = @"Oxford Thesaurus of English"; 40 | NSString * const DCSSimplifiedChineseDictionaryName = @"现代汉语规范词典"; 41 | NSString * const DCSSimplifiedChinese_EnglishDictionaryName = @"Oxford Chinese Dictionary"; 42 | NSString * const DCSSpanishDictionaryName = @"Diccionario General de la Lengua Española Vox"; 43 | NSString * const DCSWikipediaDictionaryName = @"Wikipedia"; 44 | 45 | typedef NS_ENUM(NSInteger, TTTDictionaryRecordVersion) { 46 | TTTDictionaryVersionHTML = 0, 47 | TTTDictionaryVersionHTMLWithAppCSS = 1, 48 | TTTDictionaryVersionHTMLWithPopoverCSS = 2, 49 | TTTDictionaryVersionText = 3, 50 | }; 51 | 52 | #pragma mark - 53 | 54 | extern CFArrayRef DCSCopyAvailableDictionaries(); 55 | extern CFStringRef DCSDictionaryGetName(DCSDictionaryRef dictionary); 56 | extern CFStringRef DCSDictionaryGetShortName(DCSDictionaryRef dictionary); 57 | extern DCSDictionaryRef DCSDictionaryCreate(CFURLRef url); 58 | extern CFStringRef DCSDictionaryGetName(DCSDictionaryRef dictionary); 59 | extern CFArrayRef DCSCopyRecordsForSearchString(DCSDictionaryRef dictionary, CFStringRef string, void *, void *); 60 | 61 | extern CFDictionaryRef DCSCopyDefinitionMarkup(DCSDictionaryRef dictionary, CFStringRef record); 62 | extern CFStringRef DCSRecordCopyData(CFTypeRef record, long version); 63 | extern CFStringRef DCSRecordCopyDataURL(CFTypeRef record); 64 | extern CFStringRef DCSRecordGetAnchor(CFTypeRef record); 65 | extern CFStringRef DCSRecordGetAssociatedObj(CFTypeRef record); 66 | extern CFStringRef DCSRecordGetHeadword(CFTypeRef record); 67 | extern CFStringRef DCSRecordGetRawHeadword(CFTypeRef record); 68 | extern CFStringRef DCSRecordGetString(CFTypeRef record); 69 | extern DCSDictionaryRef DCSRecordGetSubDictionary(CFTypeRef record); 70 | extern CFStringRef DCSRecordGetTitle(CFTypeRef record); 71 | 72 | #pragma mark - 73 | 74 | @interface TTTDictionaryEntry () 75 | @property (readwrite, nonatomic, copy) NSString *headword; 76 | @property (readwrite, nonatomic, copy) NSString *text; 77 | @property (readwrite, nonatomic, copy) NSString *HTML; 78 | @end 79 | 80 | @implementation TTTDictionaryEntry 81 | 82 | - (instancetype)initWithRecordRef:(CFTypeRef)record 83 | dictionaryRef:(DCSDictionaryRef)dictionary 84 | { 85 | self = [self init]; 86 | if (!self && record) { 87 | return nil; 88 | } 89 | 90 | self.headword = (__bridge NSString *)DCSRecordGetHeadword(record); 91 | if (self.headword) { 92 | self.text = (__bridge_transfer NSString*)DCSCopyTextDefinition(dictionary, (__bridge CFStringRef)self.headword, CFRangeMake(0, CFStringGetLength((__bridge CFStringRef)self.headword))); 93 | } 94 | 95 | self.HTML = (__bridge_transfer NSString *)DCSRecordCopyData(record, (long)TTTDictionaryVersionHTMLWithPopoverCSS); 96 | 97 | return self; 98 | } 99 | 100 | @end 101 | 102 | @interface TTTDictionary () 103 | @property (readwrite, nonatomic, assign) DCSDictionaryRef dictionary; 104 | @property (readwrite, nonatomic, copy) NSString *name; 105 | @property (readwrite, nonatomic, copy) NSString *shortName; 106 | @end 107 | 108 | @implementation TTTDictionary 109 | 110 | + (NSSet *)availableDictionaries { 111 | static NSSet *_availableDictionaries = nil; 112 | static dispatch_once_t onceToken; 113 | dispatch_once(&onceToken, ^{ 114 | NSMutableSet *mutableDictionaries = [NSMutableSet set]; 115 | for (id dictionary in (__bridge_transfer NSArray *)DCSCopyAvailableDictionaries()) { 116 | [mutableDictionaries addObject:[[TTTDictionary alloc] initWithDictionaryRef:(__bridge DCSDictionaryRef)dictionary]]; 117 | } 118 | 119 | _availableDictionaries = [NSSet setWithSet:mutableDictionaries]; 120 | }); 121 | 122 | return _availableDictionaries; 123 | } 124 | 125 | + (instancetype)dictionaryNamed:(NSString *)name { 126 | static NSDictionary *_availableDictionariesKeyedByName = nil; 127 | 128 | static dispatch_once_t onceToken; 129 | dispatch_once(&onceToken, ^{ 130 | NSMutableDictionary *mutableAvailableDictionariesKeyedByName = [NSMutableDictionary dictionaryWithCapacity:[[self availableDictionaries] count]]; 131 | for (TTTDictionary *dictionary in [self availableDictionaries]) { 132 | mutableAvailableDictionariesKeyedByName[dictionary.name] = dictionary; 133 | } 134 | 135 | _availableDictionariesKeyedByName = [NSDictionary dictionaryWithDictionary:mutableAvailableDictionariesKeyedByName]; 136 | }); 137 | 138 | return _availableDictionariesKeyedByName[name]; 139 | } 140 | 141 | - (instancetype)initWithDictionaryRef:(DCSDictionaryRef)dictionary { 142 | self = [self init]; 143 | if (!self || !dictionary) { 144 | return nil; 145 | } 146 | 147 | self.dictionary = dictionary; 148 | self.name = (__bridge NSString *)DCSDictionaryGetName(self.dictionary); 149 | self.shortName = (__bridge NSString *)DCSDictionaryGetShortName(self.dictionary); 150 | 151 | return self; 152 | } 153 | 154 | - (NSArray *)entriesForSearchTerm:(NSString *)term { 155 | CFRange termRange = DCSGetTermRangeInString(self.dictionary, (__bridge CFStringRef)term, 0); 156 | if (termRange.location == kCFNotFound) { 157 | return nil; 158 | } 159 | 160 | term = [term substringWithRange:NSMakeRange(termRange.location, termRange.length)]; 161 | 162 | NSArray *records = (__bridge_transfer NSArray *)DCSCopyRecordsForSearchString(self.dictionary, (__bridge CFStringRef)term, NULL, NULL); 163 | NSMutableArray *mutableEntries = [NSMutableArray arrayWithCapacity:[records count]]; 164 | if (records) { 165 | for (id record in records) { 166 | TTTDictionaryEntry *entry = [[TTTDictionaryEntry alloc] initWithRecordRef:(__bridge CFTypeRef)record dictionaryRef:self.dictionary]; 167 | if (entry) { 168 | [mutableEntries addObject:entry]; 169 | } 170 | } 171 | } 172 | 173 | return [NSArray arrayWithArray:mutableEntries]; 174 | } 175 | 176 | #pragma mark - NSObject 177 | 178 | - (BOOL)isEqual:(id)object { 179 | if (self == object) { 180 | return YES; 181 | } 182 | 183 | if (![object isKindOfClass:[TTTDictionary class]]) { 184 | return NO; 185 | } 186 | 187 | return [self.name isEqualToString:[(TTTDictionary *)object name]]; 188 | } 189 | 190 | - (NSUInteger)hash { 191 | return [self.name hash]; 192 | } 193 | 194 | @end 195 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/Example/DictionaryKit Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | F8B8BF5118CD026E00B27A52 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8B8BF5018CD026E00B27A52 /* Foundation.framework */; }; 11 | F8B8BF6F18CD0CF000B27A52 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F8B8BF6E18CD0CF000B27A52 /* CoreServices.framework */; }; 12 | F8B8BF7418CD0E5200B27A52 /* TTTDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = F8B8BF7318CD0E5200B27A52 /* TTTDictionary.m */; }; 13 | F8B8BF7618CD0E6C00B27A52 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F8B8BF7518CD0E6C00B27A52 /* main.m */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | F8B8BF4B18CD026E00B27A52 /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = /usr/share/man/man1/; 21 | dstSubfolderSpec = 0; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 1; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | F8B8BF4D18CD026E00B27A52 /* DictionaryKit Example */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "DictionaryKit Example"; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | F8B8BF5018CD026E00B27A52 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | F8B8BF5618CD026E00B27A52 /* DictionaryKit Example-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DictionaryKit Example-Prefix.pch"; sourceTree = ""; }; 32 | F8B8BF6E18CD0CF000B27A52 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; 33 | F8B8BF7118CD0E5200B27A52 /* DictionaryKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DictionaryKit.h; sourceTree = ""; }; 34 | F8B8BF7218CD0E5200B27A52 /* TTTDictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TTTDictionary.h; sourceTree = ""; }; 35 | F8B8BF7318CD0E5200B27A52 /* TTTDictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TTTDictionary.m; sourceTree = ""; }; 36 | F8B8BF7518CD0E6C00B27A52 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = SOURCE_ROOT; }; 37 | /* End PBXFileReference section */ 38 | 39 | /* Begin PBXFrameworksBuildPhase section */ 40 | F8B8BF4A18CD026E00B27A52 /* Frameworks */ = { 41 | isa = PBXFrameworksBuildPhase; 42 | buildActionMask = 2147483647; 43 | files = ( 44 | F8B8BF6F18CD0CF000B27A52 /* CoreServices.framework in Frameworks */, 45 | F8B8BF5118CD026E00B27A52 /* Foundation.framework in Frameworks */, 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | F8B8BF4418CD026E00B27A52 = { 53 | isa = PBXGroup; 54 | children = ( 55 | F8B8BF5218CD026E00B27A52 /* DictionaryKit Example */, 56 | F8B8BF4F18CD026E00B27A52 /* Frameworks */, 57 | F8B8BF4E18CD026E00B27A52 /* Products */, 58 | F8B8BF5E18CD029B00B27A52 /* Vendor */, 59 | ); 60 | sourceTree = ""; 61 | }; 62 | F8B8BF4E18CD026E00B27A52 /* Products */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | F8B8BF4D18CD026E00B27A52 /* DictionaryKit Example */, 66 | ); 67 | name = Products; 68 | sourceTree = ""; 69 | }; 70 | F8B8BF4F18CD026E00B27A52 /* Frameworks */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | F8B8BF6E18CD0CF000B27A52 /* CoreServices.framework */, 74 | F8B8BF5018CD026E00B27A52 /* Foundation.framework */, 75 | ); 76 | name = Frameworks; 77 | sourceTree = ""; 78 | }; 79 | F8B8BF5218CD026E00B27A52 /* DictionaryKit Example */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | F8B8BF7518CD0E6C00B27A52 /* main.m */, 83 | F8B8BF5518CD026E00B27A52 /* Supporting Files */, 84 | ); 85 | path = "DictionaryKit Example"; 86 | sourceTree = ""; 87 | }; 88 | F8B8BF5518CD026E00B27A52 /* Supporting Files */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | F8B8BF5618CD026E00B27A52 /* DictionaryKit Example-Prefix.pch */, 92 | ); 93 | name = "Supporting Files"; 94 | sourceTree = ""; 95 | }; 96 | F8B8BF5E18CD029B00B27A52 /* Vendor */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | F8B8BF7018CD0E5200B27A52 /* DictionaryKit */, 100 | ); 101 | name = Vendor; 102 | sourceTree = ""; 103 | }; 104 | F8B8BF7018CD0E5200B27A52 /* DictionaryKit */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | F8B8BF7118CD0E5200B27A52 /* DictionaryKit.h */, 108 | F8B8BF7218CD0E5200B27A52 /* TTTDictionary.h */, 109 | F8B8BF7318CD0E5200B27A52 /* TTTDictionary.m */, 110 | ); 111 | name = DictionaryKit; 112 | path = ../DictionaryKit; 113 | sourceTree = ""; 114 | }; 115 | /* End PBXGroup section */ 116 | 117 | /* Begin PBXNativeTarget section */ 118 | F8B8BF4C18CD026E00B27A52 /* DictionaryKit Example */ = { 119 | isa = PBXNativeTarget; 120 | buildConfigurationList = F8B8BF5B18CD026E00B27A52 /* Build configuration list for PBXNativeTarget "DictionaryKit Example" */; 121 | buildPhases = ( 122 | F8B8BF4918CD026E00B27A52 /* Sources */, 123 | F8B8BF4A18CD026E00B27A52 /* Frameworks */, 124 | F8B8BF4B18CD026E00B27A52 /* CopyFiles */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = "DictionaryKit Example"; 131 | productName = "DictionaryKit Example"; 132 | productReference = F8B8BF4D18CD026E00B27A52 /* DictionaryKit Example */; 133 | productType = "com.apple.product-type.tool"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | F8B8BF4518CD026E00B27A52 /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | LastUpgradeCheck = 0500; 142 | ORGANIZATIONNAME = "Mattt Thompson"; 143 | }; 144 | buildConfigurationList = F8B8BF4818CD026E00B27A52 /* Build configuration list for PBXProject "DictionaryKit Example" */; 145 | compatibilityVersion = "Xcode 3.2"; 146 | developmentRegion = English; 147 | hasScannedForEncodings = 0; 148 | knownRegions = ( 149 | en, 150 | ); 151 | mainGroup = F8B8BF4418CD026E00B27A52; 152 | productRefGroup = F8B8BF4E18CD026E00B27A52 /* Products */; 153 | projectDirPath = ""; 154 | projectRoot = ""; 155 | targets = ( 156 | F8B8BF4C18CD026E00B27A52 /* DictionaryKit Example */, 157 | ); 158 | }; 159 | /* End PBXProject section */ 160 | 161 | /* Begin PBXSourcesBuildPhase section */ 162 | F8B8BF4918CD026E00B27A52 /* Sources */ = { 163 | isa = PBXSourcesBuildPhase; 164 | buildActionMask = 2147483647; 165 | files = ( 166 | F8B8BF7418CD0E5200B27A52 /* TTTDictionary.m in Sources */, 167 | F8B8BF7618CD0E6C00B27A52 /* main.m in Sources */, 168 | ); 169 | runOnlyForDeploymentPostprocessing = 0; 170 | }; 171 | /* End PBXSourcesBuildPhase section */ 172 | 173 | /* Begin XCBuildConfiguration section */ 174 | F8B8BF5918CD026E00B27A52 /* Debug */ = { 175 | isa = XCBuildConfiguration; 176 | buildSettings = { 177 | ALWAYS_SEARCH_USER_PATHS = NO; 178 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 179 | CLANG_CXX_LIBRARY = "libc++"; 180 | CLANG_ENABLE_OBJC_ARC = YES; 181 | CLANG_WARN_BOOL_CONVERSION = YES; 182 | CLANG_WARN_CONSTANT_CONVERSION = YES; 183 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 184 | CLANG_WARN_EMPTY_BODY = YES; 185 | CLANG_WARN_ENUM_CONVERSION = YES; 186 | CLANG_WARN_INT_CONVERSION = YES; 187 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 188 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 189 | COPY_PHASE_STRIP = NO; 190 | GCC_C_LANGUAGE_STANDARD = gnu99; 191 | GCC_DYNAMIC_NO_PIC = NO; 192 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 193 | GCC_OPTIMIZATION_LEVEL = 0; 194 | GCC_PREPROCESSOR_DEFINITIONS = ( 195 | "DEBUG=1", 196 | "$(inherited)", 197 | ); 198 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 199 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 200 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 201 | GCC_WARN_UNDECLARED_SELECTOR = YES; 202 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 203 | GCC_WARN_UNUSED_FUNCTION = YES; 204 | GCC_WARN_UNUSED_VARIABLE = YES; 205 | MACOSX_DEPLOYMENT_TARGET = 10.9; 206 | ONLY_ACTIVE_ARCH = YES; 207 | SDKROOT = macosx; 208 | }; 209 | name = Debug; 210 | }; 211 | F8B8BF5A18CD026E00B27A52 /* Release */ = { 212 | isa = XCBuildConfiguration; 213 | buildSettings = { 214 | ALWAYS_SEARCH_USER_PATHS = NO; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 216 | CLANG_CXX_LIBRARY = "libc++"; 217 | CLANG_ENABLE_OBJC_ARC = YES; 218 | CLANG_WARN_BOOL_CONVERSION = YES; 219 | CLANG_WARN_CONSTANT_CONVERSION = YES; 220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 221 | CLANG_WARN_EMPTY_BODY = YES; 222 | CLANG_WARN_ENUM_CONVERSION = YES; 223 | CLANG_WARN_INT_CONVERSION = YES; 224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | COPY_PHASE_STRIP = YES; 227 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 228 | ENABLE_NS_ASSERTIONS = NO; 229 | GCC_C_LANGUAGE_STANDARD = gnu99; 230 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 231 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 232 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 233 | GCC_WARN_UNDECLARED_SELECTOR = YES; 234 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 235 | GCC_WARN_UNUSED_FUNCTION = YES; 236 | GCC_WARN_UNUSED_VARIABLE = YES; 237 | MACOSX_DEPLOYMENT_TARGET = 10.9; 238 | SDKROOT = macosx; 239 | }; 240 | name = Release; 241 | }; 242 | F8B8BF5C18CD026E00B27A52 /* Debug */ = { 243 | isa = XCBuildConfiguration; 244 | buildSettings = { 245 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 246 | GCC_PREFIX_HEADER = Prefix.pch; 247 | PRODUCT_NAME = "$(TARGET_NAME)"; 248 | }; 249 | name = Debug; 250 | }; 251 | F8B8BF5D18CD026E00B27A52 /* Release */ = { 252 | isa = XCBuildConfiguration; 253 | buildSettings = { 254 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 255 | GCC_PREFIX_HEADER = Prefix.pch; 256 | PRODUCT_NAME = "$(TARGET_NAME)"; 257 | }; 258 | name = Release; 259 | }; 260 | /* End XCBuildConfiguration section */ 261 | 262 | /* Begin XCConfigurationList section */ 263 | F8B8BF4818CD026E00B27A52 /* Build configuration list for PBXProject "DictionaryKit Example" */ = { 264 | isa = XCConfigurationList; 265 | buildConfigurations = ( 266 | F8B8BF5918CD026E00B27A52 /* Debug */, 267 | F8B8BF5A18CD026E00B27A52 /* Release */, 268 | ); 269 | defaultConfigurationIsVisible = 0; 270 | defaultConfigurationName = Release; 271 | }; 272 | F8B8BF5B18CD026E00B27A52 /* Build configuration list for PBXNativeTarget "DictionaryKit Example" */ = { 273 | isa = XCConfigurationList; 274 | buildConfigurations = ( 275 | F8B8BF5C18CD026E00B27A52 /* Debug */, 276 | F8B8BF5D18CD026E00B27A52 /* Release */, 277 | ); 278 | defaultConfigurationIsVisible = 0; 279 | defaultConfigurationName = Release; 280 | }; 281 | /* End XCConfigurationList section */ 282 | }; 283 | rootObject = F8B8BF4518CD026E00B27A52 /* Project object */; 284 | } 285 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/Example/DictionaryKit Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/Example/Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/Example/main.m: -------------------------------------------------------------------------------- 1 | // main.m 2 | // 3 | // Copyright (c) 2014 Mattt Thompson 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in 13 | // all copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "TTTDictionary.h" 26 | 27 | int main(int argc, const char * argv[]) { 28 | @autoreleasepool { 29 | TTTDictionary *dictionary = [TTTDictionary dictionaryNamed:DCSOxfordDictionaryOfEnglish]; 30 | NSLog(@"%@\n", dictionary.name); 31 | 32 | NSString *term = @"apple"; 33 | for (TTTDictionaryEntry *entry in [dictionary entriesForSearchTerm:term]) { 34 | NSLog(@"%@", entry.text); 35 | } 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Mattt Thompson (http://mattt.me/) 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. 20 | -------------------------------------------------------------------------------- /Frameworks/DictionaryKit/README.md: -------------------------------------------------------------------------------- 1 | # DictionaryKit 2 | 3 | **An Objective-C Wrapper for _Private_ Dictionary Services on Mac OS X** 4 | 5 | > This library accesses private OS X APIs, making it unsuitable for apps submitted to the App Store. 6 | 7 | ## Usage 8 | 9 | ```objective-c 10 | #import "DictionaryKit.h" 11 | 12 | TTTDictionary *dictionary = [TTTDictionary dictionaryNamed:DCSOxfordEnglishDictionary]; 13 | NSLog(@"%@\n", dictionary.name); 14 | 15 | NSString *term = @"apple"; 16 | for (TTTDictionaryEntry *entry in [dictionary entriesForSearchTerm:term]) { 17 | NSLog(@"%@", entry.text); 18 | } 19 | ``` 20 | 21 | ## Available Dictionaries 22 | 23 | ~~~{objective-c} 24 | NSString * const DCSAppleDictionaryName = @"Apple Dictionary"; 25 | NSString * const DCSDutchDictionaryName = @"Prisma woordenboek Nederlands"; 26 | NSString * const DCSFrenchDictionaryName = @"Multidictionnaire de la langue française"; 27 | NSString * const DCSGermanDictionaryName = @"Duden-Wissensnetz deutsche Sprache"; 28 | NSString * const DCSItalianDictionaryName = @"Dizionario italiano da un affiliato di Oxford University Press"; 29 | NSString * const DCSJapaneseSupaDaijirinDictionaryName = @"スーパー大辞林"; 30 | NSString * const DCSJapanese_EnglishDictionaryName = @"ウィズダム英和辞典 / ウィズダム和英辞典"; 31 | NSString * const DCSKoreanDictionaryName = @"New Ace Korean Language Dictionary"; 32 | NSString * const DCSKorean_EnglishDictionaryName = @"New Ace English-Korean Dictionary and New Ace Korean-English Dictionary"; 33 | NSString * const DCSNewOxfordAmericanDictionaryName = @"New Oxford American Dictionary"; 34 | NSString * const DCSOxfordAmericanWritersThesaurus = @"Oxford American Writer's Thesaurus"; 35 | NSString * const DCSOxfordDictionaryOfEnglish = @"Oxford Dictionary of English"; 36 | NSString * const DCSOxfordThesaurusOfEnglish = @"Oxford Thesaurus of English"; 37 | NSString * const DCSSimplifiedChineseDictionaryName = @"现代汉语规范词典"; 38 | NSString * const DCSSimplifiedChinese_EnglishDictionaryName = @"Oxford Chinese Dictionary"; 39 | NSString * const DCSSpanishDictionaryName = @"Diccionario General de la Lengua Española Vox"; 40 | NSString * const DCSWikipediaDictionaryName = @"Wikipedia"; 41 | ~~~ 42 | 43 | ### Contact 44 | 45 | [Mattt Thompson](http://github.com/mattt) 46 | [@mattt](https://twitter.com/mattt) 47 | 48 | ## License 49 | 50 | DictionaryKit is available under the MIT license. See the LICENSE file for more info. 51 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # OSX Dictionary CLI 2 | 3 | Access the Mac OSX Dictionary app via the command line. 4 | 5 | ## Installation 6 | 7 | - [Download the latest release](https://github.com/odlp/dictionary-osx/releases). Only available for OSX (tested on El Capitan). 8 | - Place the binary on your path, e.g. `/usr/local/bin/dictionary ` 9 | 10 | Alternatively you can build the project with Xcode 7.3 or later. After running the build (`⌘R`), right click on the `Products` group and select `Show in Finder`. 11 | 12 | ## Usage 13 | 14 | ```sh 15 | dictionary cat 16 | # cat 1 |kat| ▶noun 1 a small domesticated carnivorous mammal with soft fur... 17 | ``` 18 | 19 | ### Formats 20 | 21 | Adjust the output with `-f` or `--format` flags: 22 | 23 | - `text`: Plaintext output 24 | - `html`: Default Dictionary.app output 25 | - `speech-part`: Parses the speech part of the first definition (e.g. noun, verb) 26 | 27 | ## Background 28 | 29 | This CLI uses [DictionaryKit](https://github.com/mattt/DictionaryKit) to fetch definitions via private Dictionary Services on OSX. This private API usage is not suitable for App Store apps. Read more background about [dictionary services on NSHipster](http://nshipster.com/dictionary-services/). 30 | --------------------------------------------------------------------------------