this repo has no description
1// i'm not sure where to put this header, since it's neither a "basic" header
2// nor a framework header (it doesn't even have it's own library from what i can tell)
3
4#ifndef _SOFTLINKING_SOFTLINKING_H_
5#define _SOFTLINKING_SOFTLINKING_H_
6
7#import <Foundation/Foundation.h>
8#import <CoreFoundation/CoreFoundation.h>
9#import <dispatch/dispatch.h>
10#include <dlfcn.h>
11
12// certain aspects of this file (such as framework, function, and constant loading)
13// can be implemented in plain C, but because it can also load Objective-C classes,
14// we have to use `NSBundle`s too, which are Objective-C only
15//
16// that's okay, though, because it this only seems to be used in Objective-C code
17
18#define SOFT_LINK_STRINGIFY_INTERNAL2(x) #x
19#define SOFT_LINK_STRINGIFY_INTERNAL1(x) SOFT_LINK_STRINGIFY_INTERNAL2(x)
20#define SOFT_LINK_NSSTRINGIFY(x) @ SOFT_LINK_STRINGIFY_INTERNAL1(x)
21#define SOFT_LINK_CFSTRINGIFY(x) CFSTR(SOFT_LINK_STRINGIFY_INTERNAL1(x))
22
23// STUB/HACK: For now just redirect to SOFT_LINK_FRAMEWORK
24#define SOFT_LINK_OPTIONAL_FRAMEWORK(_location, _name) SOFT_LINK_FRAMEWORK(_location,_name)
25
26#define SOFT_LINK_FRAMEWORK(_location, _name) \
27 static CFBundleRef softlink_get_cfbundle_ ## _name () { \
28 static CFBundleRef bundle = NULL; \
29 static dispatch_once_t once_handle; \
30 dispatch_once(&once_handle, ^{ \
31 CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/" #_location "/" #_name ".framework"), kCFURLPOSIXPathStyle, true); \
32 if (!url) \
33 return; \
34 bundle = CFBundleCreate(kCFAllocatorDefault, url); \
35 CFRelease(url); \
36 }); \
37 return bundle; \
38 }; \
39 static NSBundle* softlink_get_nsbundle_ ## _name () { \
40 static NSBundle* bundle = nil; \
41 static dispatch_once_t once_handle; \
42 dispatch_once(&once_handle, ^{ \
43 NSString* path = @"/System/Library/" #_location "/" #_name ".framework"; \
44 bundle = [NSBundle bundleWithPath: path]; \
45 }); \
46 return bundle; \
47 }; \
48 static int is ## _name ## Available () { \
49 /* this is probably not the best way to do this */ \
50 if (softlink_get_cfbundle_ ## _name ()) \
51 return 1; \
52 return 0; \
53 };
54
55// not sure what the difference between safe and regular is
56#define SOFT_LINK_FRAMEWORK_SAFE(_location, _name) SOFT_LINK_FRAMEWORK(_location, _name)
57
58#define SOFT_LINK_CLASS(_framework, _name) \
59 static Class get ## _name ## Class () { \
60 static Class class = Nil; \
61 static dispatch_once_t once_handle; \
62 dispatch_once(&once_handle, ^{ \
63 NSBundle* bundle = softlink_get_nsbundle_ ## _framework (); \
64 class = [bundle classNamed: SOFT_LINK_NSSTRINGIFY(_name)]; \
65 }); \
66 return class; \
67 };
68
69#define SOFT_LINK_CONSTANT(_framework, _name, _type) \
70 static _type get ## _name () { \
71 static _type const* constant = NULL; \
72 static dispatch_once_t once_handle; \
73 dispatch_once(&once_handle, ^{ \
74 CFBundleRef bundle = softlink_get_cfbundle_ ## _framework (); \
75 if (bundle) \
76 constant = (_type const*)CFBundleGetDataPointerForName(bundle, SOFT_LINK_CFSTRINGIFY(_name)); \
77 }); \
78 /*
79 i'm not sure what to do if the symbol can't be found since
80 there's no way to tell the caller that an error occurred
81 */ \
82 return *constant; \
83 };
84
85// i'm unsure about that last macro parameter: `_call_pattern`
86// it seems to just be a repetition of the parameter names
87// but i'm guessing that that would be used to modify the arguments to the "soft" variant before passing
88// them onto the "hard" function
89#define SOFT_LINK_FUNCTION(_framework, _name, _soft_name, _return_type, _parameters, _call_pattern) \
90 static _return_type _soft_name _parameters { \
91 static _return_type (*func) _parameters = NULL; \
92 static dispatch_once_t once_handle; \
93 dispatch_once(&once_handle, ^{ \
94 CFBundleRef bundle = softlink_get_cfbundle_ ## _framework (); \
95 if (bundle) \
96 func = CFBundleGetFunctionPointerForName(bundle, SOFT_LINK_CFSTRINGIFY(_name)); \
97 }); \
98 /* again, here i'm unsure about what to do if the symbol's not there */ \
99 return func _call_pattern; \
100 };
101
102#endif // _SOFTLINKING_SOFTLINKING_H_