this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge remote-tracking branch 'origin/master' into using-machos-experiment

+152
+152
tools/stub-gen-objc
··· 1 + #!/usr/bin/env swift 2 + /* 3 + This file is part of Darling. 4 + 5 + Copyright (C) 2017 Lubos Dolezel 6 + 7 + Darling is free software: you can redistribute it and/or modify 8 + it under the terms of the GNU General Public License as published by 9 + the Free Software Foundation, either version 3 of the License, or 10 + (at your option) any later version. 11 + 12 + Darling is distributed in the hope that it will be useful, 13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + GNU General Public License for more details. 16 + 17 + You should have received a copy of the GNU General Public License 18 + along with Darling. If not, see <http://www.gnu.org/licenses/>. 19 + */ 20 + 21 + import Foundation 22 + 23 + guard CommandLine.arguments.count == 3 else { 24 + fatalError("Usage: \(CommandLine.arguments[0]) <Objective-C binary> <output directory>") 25 + } 26 + 27 + let copyright = "/*\n" + 28 + "This file is part of Darling.\n" + 29 + "\n" + 30 + 31 + "Copyright (C) 2017 Lubos Dolezel\n" + 32 + "\n" + 33 + 34 + "Darling is free software: you can redistribute it and/or modify\n" + 35 + "it under the terms of the GNU General Public License as published by\n" + 36 + "the Free Software Foundation, either version 3 of the License, or\n" + 37 + "(at your option) any later version.\n" + 38 + "\n" + 39 + 40 + "Darling is distributed in the hope that it will be useful,\n" + 41 + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + 42 + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + 43 + "GNU General Public License for more details.\n" + 44 + "\n" + 45 + 46 + "You should have received a copy of the GNU General Public License\n" + 47 + "along with Darling. If not, see <http://www.gnu.org/licenses/>.\n" + 48 + "*/\n\n" 49 + 50 + let name = CommandLine.arguments[1] 51 + let outputDirectory = CommandLine.arguments[2] 52 + 53 + // So we can generate a "master header" 54 + var moduleName = (name as NSString).pathComponents.last! as String 55 + 56 + // Set up the environment for class-dump 57 + let pipe = Pipe() 58 + 59 + let classDump = Process() 60 + classDump.launchPath = "/bin/bash" 61 + classDump.arguments = ["-c","class-dump \(name)"] 62 + classDump.standardOutput = pipe 63 + 64 + // Redirect the output 65 + let outHandle = pipe.fileHandleForReading 66 + 67 + var output = "" 68 + 69 + // Put the output in the string output 70 + outHandle.readabilityHandler = { pipe in 71 + if let line = String(data: pipe.availableData, encoding: String.Encoding.utf8) { 72 + output.append(line) 73 + } else { 74 + print("Error decoding data: \(pipe.availableData)") 75 + } 76 + } 77 + 78 + // Run it and wait for it to finish 79 + classDump.launch() 80 + classDump.waitUntilExit() 81 + 82 + var classes: [(class: String, superclass: String)] = [] 83 + 84 + // Begin ugly string parsing code 85 + while output.contains("@interface") { 86 + let interfaceRange = output.range(of: "@interface")! 87 + output.removeSubrange(output.startIndex ... interfaceRange.upperBound) 88 + if let space = output.range(of: " : ") { 89 + let className = output[output.startIndex ..< space.lowerBound] 90 + 91 + output.removeSubrange(output.startIndex ..< space.upperBound) 92 + 93 + var endOfSuperclass: String.CharacterView.Index! 94 + let nextNewline = output.range(of: "\n") 95 + let nextProtocolConformance = output.range(of: " <") 96 + if nextNewline != nil && nextProtocolConformance != nil { 97 + endOfSuperclass = nextNewline!.lowerBound < nextProtocolConformance!.lowerBound ? nextNewline!.lowerBound : nextProtocolConformance!.lowerBound 98 + } else if nextNewline != nil { 99 + endOfSuperclass = nextNewline!.lowerBound 100 + } else if nextProtocolConformance != nil { 101 + endOfSuperclass = nextProtocolConformance!.lowerBound 102 + } else { 103 + fatalError("Failed to detect superclass: \(className)") 104 + } 105 + let superclass = output[output.startIndex ..< endOfSuperclass] 106 + 107 + classes.append((class: className, superclass: superclass)) 108 + } 109 + } 110 + // End ugly string parsing code 111 + 112 + // Create destination folders if they don't exist 113 + try FileManager.default.createDirectory(atPath: outputDirectory, withIntermediateDirectories: true) 114 + try FileManager.default.createDirectory(atPath: outputDirectory + "/Headers", withIntermediateDirectories: true) 115 + try FileManager.default.createDirectory(atPath: outputDirectory + "/Sources", withIntermediateDirectories: true) 116 + 117 + // Emit master header 118 + var mh = copyright 119 + mh += "#import <Foundation/Foundation.h>\n" 120 + 121 + // Generate headers and sources for each class 122 + for var classEntry in classes { 123 + 124 + mh += "#import <\(moduleName)/\(classEntry.class).h>\n" 125 + 126 + var header = copyright 127 + 128 + header += "@interface \(classEntry.class) : \(classEntry.superclass)\n\n" 129 + 130 + header += "@end\n" 131 + 132 + var implementation = copyright 133 + 134 + implementation += "#import <\(moduleName)/\(moduleName).h>\n\n" 135 + 136 + implementation += "@implementation \(classEntry.class)\n\n" 137 + 138 + implementation += "- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {\n" 139 + implementation += " return [NSMethodSignature signatureWithObjCTypes: \"v@:\"];\n" 140 + implementation += "}\n\n" 141 + 142 + implementation += "- (void)forwardInvocation:(NSInvocation *)anInvocation {\n" 143 + implementation += " NSLog(@\"Stub called: %@ in %@\", NSStringFromSelector([anInvocation selector]), [self class]);\n" 144 + implementation += "}\n\n" 145 + 146 + implementation += "@end\n" 147 + 148 + try header.write(toFile: outputDirectory + "/Headers/" + classEntry.class + ".h", atomically: false, encoding: String.Encoding.utf8) 149 + try implementation.write(toFile: outputDirectory + "/Sources/" + classEntry.class + ".m", atomically: false, encoding: String.Encoding.utf8) 150 + } 151 + 152 + try mh.write(toFile: outputDirectory + "/Headers/" + moduleName + ".h", atomically: false, encoding: String.Encoding.utf8)