1// Reads selector names on stdin and prints those no class on this system implements,
2// instance or class side: calls a 10.6 binary could make that would raise at run time.
3// `strings BINARY` supplies candidates; names that were never selectors print too.
4// Method lists are read directly: asking a class resolves methods, which some raise.
5#include <dlfcn.h>
6#include <objc/runtime.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11static int compare(const void *a, const void *b) {
12 return strcmp(*(const char *const *)a, *(const char *const *)b);
13}
14
15int main(void) {
16 const char *frameworks[] = {"AppKit", "Carbon", "QuartzCore", "Security", "OpenGL"};
17 for (size_t i = 0; i < sizeof frameworks / sizeof *frameworks; i++) {
18 char path[256];
19 snprintf(path, sizeof path, "/System/Library/Frameworks/%s.framework/%s", frameworks[i], frameworks[i]);
20 dlopen(path, RTLD_NOW);
21 }
22 int count = objc_getClassList(NULL, 0);
23 Class *classes = malloc(sizeof(Class) * count);
24 objc_getClassList(classes, count);
25 size_t names = 0, capacity = 1 << 16;
26 const char **known = malloc(sizeof(char *) * capacity);
27 for (int i = 0; i < count * 2; i++) {
28 Class cls = i < count ? classes[i] : object_getClass((id)classes[i - count]);
29 unsigned methods = 0;
30 Method *list = class_copyMethodList(cls, &methods);
31 for (unsigned m = 0; m < methods; m++) {
32 if (names == capacity) known = realloc(known, sizeof(char *) * (capacity *= 2));
33 known[names++] = sel_getName(method_getName(list[m]));
34 }
35 free(list);
36 }
37 qsort(known, names, sizeof(char *), compare);
38 char line[1024];
39 while (fgets(line, sizeof line, stdin)) {
40 line[strcspn(line, "\n")] = 0;
41 const char *name = line;
42 if (!bsearch(&name, known, names, sizeof(char *), compare)) puts(line);
43 }
44 return 0;
45}