Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153#!/usr/bin/env swift/*This file is part of Darling.Copyright (C) 2017 Lubos DolezelDarling is free software: you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation, either version 3 of the License, or(at your option) any later version. Darling is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details. You should have received a copy of the GNU General Public Licensealong with Darling. If not, see <http://www.gnu.org/licenses/>.*/import Foundationguard CommandLine.arguments.count == 3 else { fatalError("Usage: \(CommandLine.arguments[0]) <Objective-C binary> <output directory>")}let copyright = "/*\n" + "This file is part of Darling.\n" + "\n" + "Copyright (C) 2018 Lubos Dolezel\n" + "\n" + "Darling is free software: you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation, either version 3 of the License, or\n" + "(at your option) any later version.\n" + "\n" + "Darling is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n" + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with Darling. If not, see <http://www.gnu.org/licenses/>.\n" + "*/\n\n"let name = CommandLine.arguments[1]let outputDirectory = CommandLine.arguments[2]// So we can generate a "master header"var moduleName = (name as NSString).pathComponents.last! as String// Set up the environment for class-dumplet pipe = Pipe()let classDump = Process()classDump.launchPath = "/bin/bash"classDump.arguments = ["-c","class-dump \(name)"]classDump.standardOutput = pipe// Redirect the outputlet outHandle = pipe.fileHandleForReadingvar output = ""// Put the output in the string outputoutHandle.readabilityHandler = { pipe in if let line = String(data: pipe.availableData, encoding: String.Encoding.utf8) { output.append(line) } else { print("Error decoding data: \(pipe.availableData)") }}// Run it and wait for it to finishclassDump.launch()classDump.waitUntilExit()var classes: [(class: String, superclass: String)] = []// Begin ugly string parsing codewhile output.contains("@interface") { let interfaceRange = output.range(of: "@interface")! output.removeSubrange(output.startIndex ... interfaceRange.upperBound) if let space = output.range(of: " : ") { let className = output[output.startIndex ..< space.lowerBound] output.removeSubrange(output.startIndex ..< space.upperBound) var endOfSuperclass: String.Index! let nextNewline = output.range(of: "\n") let nextProtocolConformance = output.range(of: " <") if nextNewline != nil && nextProtocolConformance != nil { endOfSuperclass = nextNewline!.lowerBound < nextProtocolConformance!.lowerBound ? nextNewline!.lowerBound : nextProtocolConformance!.lowerBound } else if nextNewline != nil { endOfSuperclass = nextNewline!.lowerBound } else if nextProtocolConformance != nil { endOfSuperclass = nextProtocolConformance!.lowerBound } else { fatalError("Failed to detect superclass: \(className)") } let superclass = output[output.startIndex ..< endOfSuperclass] classes.append((class: String(className), superclass: String(superclass))) }}// End ugly string parsing code// Create destination folders if they don't existtry FileManager.default.createDirectory(atPath: outputDirectory, withIntermediateDirectories: true)try FileManager.default.createDirectory(atPath: outputDirectory + "/Headers", withIntermediateDirectories: true)try FileManager.default.createDirectory(atPath: outputDirectory + "/Sources", withIntermediateDirectories: true)// Emit master headervar mh = copyrightmh += "#import <Foundation/Foundation.h>\n"// Generate headers and sources for each classfor classEntry in classes { mh += "#import <\(moduleName)/\(classEntry.class).h>\n" var header = copyright header += "@interface \(classEntry.class) : \(classEntry.superclass)\n\n" header += "@end\n" var implementation = copyright implementation += "#import <\(moduleName)/\(moduleName).h>\n\n" implementation += "@implementation \(classEntry.class)\n\n" implementation += "- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {\n" implementation += " return [NSMethodSignature signatureWithObjCTypes: \"v@:\"];\n" implementation += "}\n\n" implementation += "- (void)forwardInvocation:(NSInvocation *)anInvocation {\n" implementation += " NSLog(@\"Stub called: %@ in %@\", NSStringFromSelector([anInvocation selector]), [self class]);\n" implementation += "}\n\n" implementation += "@end\n" try header.write(toFile: outputDirectory + "/Headers/" + classEntry.class + ".h", atomically: false, encoding: String.Encoding.utf8) try implementation.write(toFile: outputDirectory + "/Sources/" + classEntry.class + ".m", atomically: false, encoding: String.Encoding.utf8)}try mh.write(toFile: outputDirectory + "/Headers/" + moduleName + ".h", atomically: false, encoding: String.Encoding.utf8)