Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 1034 lines (913 sloc) 26.17 kb
65c5fb4 implemented informal protocol method definition + some refactoring
Laurent Sansonetti authored
1 /*
2 * MacRuby ObjC helpers.
9c1d230 committing experimental branch content
Laurent Sansonetti authored
3 *
65c5fb4 implemented informal protocol method definition + some refactoring
Laurent Sansonetti authored
4 * This file is covered by the Ruby license. See COPYING for more details.
7d7d3e8 @ferrous26 Change ownership to The MacRuby Team and update copyrights
ferrous26 authored
5 *
6 * Copyright (C) 2012, The MacRuby Team. All rights reserved.
9595725 update copyrights to 2011
Laurent Sansonetti authored
7 * Copyright (C) 2007-2011, Apple Inc. All rights reserved.
9c1d230 committing experimental branch content
Laurent Sansonetti authored
8 */
9
10 #include <Foundation/Foundation.h>
d0898dd include/ruby/macruby.h -> macruby_internal.h
Laurent Sansonetti authored
11 #include "macruby_internal.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
12 #include "ruby/node.h"
13 #include "ruby/encoding.h"
14 #include "ruby/objc.h"
cb65416 the great schism, part I
Laurent Sansonetti authored
15 #include "vm.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
16 #include "objc.h"
17 #include "id.h"
311a41b rewrote class flags to not use the version field anymore, better typing ...
Laurent Sansonetti authored
18 #include "class.h"
f024e51 @lrz when relocating the load path when MacRuby.framework is embedded, make s...
lrz authored
19 #include "version.h"
9c1d230 committing experimental branch content
Laurent Sansonetti authored
20
21 #include <unistd.h>
22 #include <dlfcn.h>
23 #include <mach-o/dyld.h>
24 #include <sys/mman.h>
25 #if HAVE_BRIDGESUPPORT_FRAMEWORK
26 # include <BridgeSupport/BridgeSupport.h>
27 #else
28 # include "bs.h"
29 #endif
30
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
31 bool
65c5fb4 implemented informal protocol method definition + some refactoring
Laurent Sansonetti authored
32 rb_objc_get_types(VALUE recv, Class klass, SEL sel, Method method,
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
33 bs_element_method_t *bs_method, char *buf, size_t buflen)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
34 {
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
35 const char *type;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
36 unsigned i;
37
6418ac7 define our own version of method_getNumberOfArguments() since the system...
Laurent Sansonetti authored
38 memset(buf, 0, buflen);
39
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
40 if (method != NULL) {
41 if (bs_method == NULL) {
42 type = method_getTypeEncoding(method);
43 assert(strlen(type) < buflen);
44 buf[0] = '\0';
45 do {
46 const char *type2 = SkipFirstType(type);
47 strncat(buf, type, type2 - type);
48 type = SkipStackSize(type2);
49 }
50 while (*type != '\0');
51 }
52 else {
53 char buf2[100];
54 type = rb_get_bs_method_type(bs_method, -1);
55 if (type != NULL) {
56 strlcpy(buf, type, buflen);
57 }
58 else {
59 method_getReturnType(method, buf2, sizeof buf2);
60 strlcpy(buf, buf2, buflen);
61 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
62
6418ac7 define our own version of method_getNumberOfArguments() since the system...
Laurent Sansonetti authored
63 const unsigned int argc = rb_method_getNumberOfArguments(method);
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
64 for (i = 0; i < argc; i++) {
65 if (i >= 2 && (type = rb_get_bs_method_type(bs_method, i - 2))
66 != NULL) {
67 strlcat(buf, type, buflen);
68 }
69 else {
70 method_getArgumentType(method, i, buf2, sizeof(buf2));
71 strlcat(buf, buf2, buflen);
72 }
73 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
74 }
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
75 return true;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
76 }
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
77 else if (!SPECIAL_CONST_P(recv)) {
78 NSMethodSignature *msig = [(id)recv methodSignatureForSelector:sel];
79 if (msig != NULL) {
80 unsigned i;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
81
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
82 type = rb_get_bs_method_type(bs_method, -1);
83 if (type == NULL) {
84 type = [msig methodReturnType];
85 }
86 strlcpy(buf, type, buflen);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
87
6418ac7 define our own version of method_getNumberOfArguments() since the system...
Laurent Sansonetti authored
88 const int argc = [msig numberOfArguments];
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
89 for (i = 0; i < argc; i++) {
90 if (i < 2 || (type = rb_get_bs_method_type(bs_method, i - 2))
91 == NULL) {
92 type = [msig getArgumentTypeAtIndex:i];
93 }
94 strlcat(buf, type, buflen);
95 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
96
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
97 return true;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
98 }
99 }
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
100 return false;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
101 }
102
c306298 fixed the NSNumber conversion (which broke NSProxy), moved the support f...
Laurent Sansonetti authored
103 bool
104 rb_objc_supports_forwarding(VALUE recv, SEL sel)
105 {
106 if (!SPECIAL_CONST_P(recv)) {
3998ca5 @lrz don't crash when messaging methodSignatureForSelector: to NSProxy class ...
lrz authored
107 @try {
108 // Protect the call since it may throw an exception when called on
109 // NSProxy class or instance.
110 return [(id)recv methodSignatureForSelector:sel] != nil;
111 }
112 @catch (id exc) {
113 return false;
114 }
c306298 fixed the NSNumber conversion (which broke NSProxy), moved the support f...
Laurent Sansonetti authored
115 }
116 return false;
117 }
118
55b12f3 fix calls to -[NSString fileSystemRepresentation] to catch potential exc...
Laurent Sansonetti authored
119 static const char *
120 fileSystemPath(NSString *str)
121 {
122 @try {
123 return [str fileSystemRepresentation];
124 }
125 @catch (id exc) {
126 // Sometimes, -fileSystemRepresentation can fail.
127 }
128 return [str UTF8String];
129 }
130
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
131 VALUE
b8a4224 Improve core/Dir pass rate
Thibault Martin-Lagardette authored
132 rb_home_dir(VALUE user_name)
133 {
134 NSString *user = nil;
135 NSString *home_dir = nil;
136
137 if (user_name != Qnil) {
138 user = (NSString *)user_name;
139 home_dir = NSHomeDirectoryForUser(user);
140 if (home_dir == nil) {
141 rb_raise(rb_eArgError, "user %s doesn't exist",
142 [user UTF8String]);
143 }
144 }
145 else {
146 home_dir = NSHomeDirectory();
147 if (home_dir == nil) {
148 return Qnil;
149 }
150 }
55b12f3 fix calls to -[NSString fileSystemRepresentation] to catch potential exc...
Laurent Sansonetti authored
151 return rb_str_new2(fileSystemPath(home_dir));
b8a4224 Improve core/Dir pass rate
Thibault Martin-Lagardette authored
152 }
153
4a89e89 fix File.expand_path to not resolve symlinks
Laurent Sansonetti authored
154 static bool
155 is_absolute_path(NSString *path, bool expand_tilde)
146d166 Improve core/file pass rate
Thibault Martin-Lagardette authored
156 {
157 if (!expand_tilde && [path isAbsolutePath] && [path hasPrefix:@"~"]) {
4a89e89 fix File.expand_path to not resolve symlinks
Laurent Sansonetti authored
158 return false;
146d166 Improve core/file pass rate
Thibault Martin-Lagardette authored
159 }
160 return [path isAbsolutePath];
161 }
162
163 static VALUE
4a89e89 fix File.expand_path to not resolve symlinks
Laurent Sansonetti authored
164 file_expand_path(VALUE fname, VALUE dname, bool absolute)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
165 {
856b56b @alloy Fixed File.expand_path, removed all tags.
alloy authored
166 NSString *res = (NSString *)FilePathValue(fname);
167
146d166 Improve core/file pass rate
Thibault Martin-Lagardette authored
168 if (is_absolute_path(res, !absolute)) {
4a89e89 fix File.expand_path to not resolve symlinks
Laurent Sansonetti authored
169 // Resolve symlinks only in absolute mode.
170 NSString *tmp = absolute
171 ? [res stringByResolvingSymlinksInPath]
172 : [[res stringByExpandingTildeInPath] stringByStandardizingPath];
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
173 // Make sure we don't have an invalid user path.
59746d9 cleaning up a few things
Laurent Sansonetti authored
174 if ([res hasPrefix:@"~"] && [tmp isEqualToString:res]) {
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
175 NSString *user = [[[res pathComponents] objectAtIndex:0]
176 substringFromIndex:1];
177 rb_raise(rb_eArgError, "user %s doesn't exist", [user UTF8String]);
178 }
179 res = tmp;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
180 }
856b56b @alloy Fixed File.expand_path, removed all tags.
alloy authored
181 else {
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
182 NSString *dir = dname != Qnil
183 ? (NSString *)FilePathValue(dname)
184 : [[NSFileManager defaultManager] currentDirectoryPath];
856b56b @alloy Fixed File.expand_path, removed all tags.
alloy authored
185
146d166 Improve core/file pass rate
Thibault Martin-Lagardette authored
186 if (!is_absolute_path(dir, !absolute)) {
187 dir = (NSString *)file_expand_path((VALUE)dir, Qnil, 0);
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
188 }
856b56b @alloy Fixed File.expand_path, removed all tags.
alloy authored
189
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
190 // stringByStandardizingPath does not expand "/." to "/".
59746d9 cleaning up a few things
Laurent Sansonetti authored
191 if ([res isEqualToString:@"."] && [dir isEqualToString:@"/"]) {
1087f37 make sure File.join and File.expand_path return RubyStrings (for now)
Laurent Sansonetti authored
192 res = @"/";
193 }
194 else {
195 res = [[dir stringByAppendingPathComponent:res]
196 stringByStandardizingPath];
197 }
856b56b @alloy Fixed File.expand_path, removed all tags.
alloy authored
198 }
199
55b12f3 fix calls to -[NSString fileSystemRepresentation] to catch potential exc...
Laurent Sansonetti authored
200 return rb_str_new2(fileSystemPath(res));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
201 }
202
146d166 Improve core/file pass rate
Thibault Martin-Lagardette authored
203 VALUE
204 rb_file_expand_path(VALUE fname, VALUE dname)
205 {
206 return file_expand_path(fname, dname, 0);
207 }
208
209 VALUE
210 rb_file_absolute_path(VALUE fname, VALUE dname)
211 {
212 return file_expand_path(fname, dname, 1);
213 }
214
9c1d230 committing experimental branch content
Laurent Sansonetti authored
215 static VALUE
216 rb_objc_load_bs(VALUE recv, SEL sel, VALUE path)
217 {
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
218 #if MACRUBY_STATIC
219 not_implemented_in_static(sel);
220 #else
caf0939 some work on C structures support
Laurent Sansonetti authored
221 rb_vm_load_bridge_support(StringValuePtr(path), NULL, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
222 return recv;
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
223 #endif
9c1d230 committing experimental branch content
Laurent Sansonetti authored
224 }
225
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
226 #if !defined(MACRUBY_STATIC)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
227 static void
228 rb_objc_search_and_load_bridge_support(const char *framework_path)
229 {
230 char path[PATH_MAX];
231
232 if (bs_find_path(framework_path, path, sizeof path)) {
caf0939 some work on C structures support
Laurent Sansonetti authored
233 rb_vm_load_bridge_support(path, framework_path,
9c1d230 committing experimental branch content
Laurent Sansonetti authored
234 BS_PARSE_OPTIONS_LOAD_DYLIBS);
235 }
236 }
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
237 #endif
9c1d230 committing experimental branch content
Laurent Sansonetti authored
238
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
239 bool rb_objc_enable_ivar_set_kvo_notifications = false;
0583c82 @alloy Once any framework is loaded, send KVO notifications from attr writers.
alloy authored
240
9c1d230 committing experimental branch content
Laurent Sansonetti authored
241 VALUE
242 rb_require_framework(VALUE recv, SEL sel, int argc, VALUE *argv)
243 {
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
244 #if MACRUBY_STATIC
245 not_implemented_in_static(sel);
246 #else
9c1d230 committing experimental branch content
Laurent Sansonetti authored
247 VALUE framework;
248 VALUE search_network;
249 const char *cstr;
250 NSFileManager *fileManager;
251 NSString *path;
252 NSBundle *bundle;
253 NSError *error;
0044160 fix for #12, support DYLD_FRAMEWORK_PATH for framework load (patch by ma...
Laurent Sansonetti authored
254
9c1d230 committing experimental branch content
Laurent Sansonetti authored
255 rb_scan_args(argc, argv, "11", &framework, &search_network);
256
257 Check_Type(framework, T_STRING);
258 cstr = RSTRING_PTR(framework);
259
260 fileManager = [NSFileManager defaultManager];
261 path = [fileManager stringWithFileSystemRepresentation:cstr
262 length:strlen(cstr)];
263
87ef594 @lrz fix a bug in Kernel#framework when a file in the current directory match...
lrz authored
264 if ([path isAbsolutePath]
265 || [[path pathExtension] isEqualToString:@"framework"]
266 || [[path pathComponents] count] > 1) {
267 // filesystem path is given
268 BOOL pathIsDirectory = NO;
269 if (![fileManager fileExistsAtPath:path isDirectory:&pathIsDirectory]
270 || pathIsDirectory == NO) {
271 rb_raise(rb_eRuntimeError,
272 "path `%s' doesn't exist or isn't a framework", cstr);
273 }
274 }
275 else {
276 // framework name is given
9c1d230 committing experimental branch content
Laurent Sansonetti authored
277 NSSearchPathDomainMask pathDomainMask;
278 NSString *frameworkName;
279 NSArray *dirs;
280 NSUInteger i, count;
281
282 cstr = NULL;
283
284 #define FIND_LOAD_PATH_IN_LIBRARY(dir) \
285 do { \
286 path = [[dir stringByAppendingPathComponent:@"Frameworks"] \
287 stringByAppendingPathComponent:frameworkName]; \
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
288 if ([fileManager fileExistsAtPath:path]) { \
9c1d230 committing experimental branch content
Laurent Sansonetti authored
289 goto success; \
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
290 } \
9c1d230 committing experimental branch content
Laurent Sansonetti authored
291 path = [[dir stringByAppendingPathComponent:@"PrivateFrameworks"] \
292 stringByAppendingPathComponent:frameworkName]; \
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
293 if ([fileManager fileExistsAtPath:path]) { \
9c1d230 committing experimental branch content
Laurent Sansonetti authored
294 goto success; \
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
295 } \
9c1d230 committing experimental branch content
Laurent Sansonetti authored
296 } \
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
297 while (0)
9c1d230 committing experimental branch content
Laurent Sansonetti authored
298
299 pathDomainMask = RTEST(search_network)
300 ? NSAllDomainsMask
301 : NSUserDomainMask | NSLocalDomainMask | NSSystemDomainMask;
302
303 frameworkName = [path stringByAppendingPathExtension:@"framework"];
304
305 path = [[[[NSBundle mainBundle] bundlePath]
306 stringByAppendingPathComponent:@"Contents/Frameworks"]
307 stringByAppendingPathComponent:frameworkName];
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
308 if ([fileManager fileExistsAtPath:path]) {
309 goto success;
310 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
311
312 dirs = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
313 pathDomainMask, YES);
314 for (i = 0, count = [dirs count]; i < count; i++) {
315 NSString *dir = [dirs objectAtIndex:i];
316 FIND_LOAD_PATH_IN_LIBRARY(dir);
317 }
318
319 dirs = NSSearchPathForDirectoriesInDomains(NSDeveloperDirectory,
320 pathDomainMask, YES);
321 for (i = 0, count = [dirs count]; i < count; i++) {
322 NSString *dir = [[dirs objectAtIndex:i]
323 stringByAppendingPathComponent:@"Library"];
324 FIND_LOAD_PATH_IN_LIBRARY(dir);
325 }
0044160 fix for #12, support DYLD_FRAMEWORK_PATH for framework load (patch by ma...
Laurent Sansonetti authored
326
327 dirs = [[[[NSProcessInfo processInfo] environment] valueForKey:@"DYLD_FRAMEWORK_PATH"] componentsSeparatedByString: @":"];
328 for (i = 0, count = [dirs count]; i < count; i++) {
329 NSString *dir = [dirs objectAtIndex:i];
330 path = [dir stringByAppendingPathComponent:frameworkName];
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
331 if ([fileManager fileExistsAtPath:path]) {
0044160 fix for #12, support DYLD_FRAMEWORK_PATH for framework load (patch by ma...
Laurent Sansonetti authored
332 goto success;
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
333 }
0044160 fix for #12, support DYLD_FRAMEWORK_PATH for framework load (patch by ma...
Laurent Sansonetti authored
334 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
335
336 #undef FIND_LOAD_PATH_IN_LIBRARY
337
338 rb_raise(rb_eRuntimeError, "framework `%s' not found",
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
339 RSTRING_PTR(framework));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
340 }
341
342 success:
343
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
344 if (cstr == NULL) {
55b12f3 fix calls to -[NSString fileSystemRepresentation] to catch potential exc...
Laurent Sansonetti authored
345 cstr = fileSystemPath(path);
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
346 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
347
348 bundle = [NSBundle bundleWithPath:path];
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
349 if (bundle == nil) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
350 rb_raise(rb_eRuntimeError,
351 "framework at path `%s' cannot be located",
352 cstr);
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
353 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
354
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
355 const bool loaded = [bundle isLoaded];
356 if (!loaded && ![bundle loadAndReturnError:&error]) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
357 rb_raise(rb_eRuntimeError,
358 "framework at path `%s' cannot be loaded: %s",
359 cstr,
360 [[error description] UTF8String]);
361 }
362
363 rb_objc_search_and_load_bridge_support(cstr);
364
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
365 rb_objc_enable_ivar_set_kvo_notifications = true;
0583c82 @alloy Once any framework is loaded, send KVO notifications from attr writers.
alloy authored
366
4fc70c2 Fixes #669 + some style
Thibault Martin-Lagardette authored
367 return loaded ? Qfalse : Qtrue;
a6a5d3e started to trim out the static library
Laurent Sansonetti authored
368 #endif
9c1d230 committing experimental branch content
Laurent Sansonetti authored
369 }
370
290673a don't forget to initialize the shared compiler in macruby_main() too
Laurent Sansonetti authored
371 void rb_vm_init_compiler(void);
372
f0291bf define -allocWithZone: and not -alloc on every new Ruby class
Laurent Sansonetti authored
373 static void
9c1d230 committing experimental branch content
Laurent Sansonetti authored
374 rb_objc_kvo_setter_imp(void *recv, SEL sel, void *value)
375 {
376 const char *selname;
377 char buf[128];
378 size_t s;
379
380 selname = sel_getName(sel);
381 buf[0] = '@';
382 buf[1] = tolower(selname[3]);
383 s = strlcpy(&buf[2], &selname[4], sizeof buf - 2);
384 buf[s + 1] = '\0';
385
637ca0f removing extra fat out of objc.m
Laurent Sansonetti authored
386 rb_ivar_set((VALUE)recv, rb_intern(buf), value == NULL
387 ? Qnil : OC2RB(value));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
388 }
389
390 /*
391 Defines an attribute writer method which conforms to Key-Value Coding.
392 (See http://developer.apple.com/documentation/Cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html)
393
394 attr_accessor :foo
395
396 Will create the normal accessor methods, plus <tt>setFoo</tt>
397
398 TODO: Does not handle the case were the user might override #foo=
399 */
400 void
401 rb_objc_define_kvo_setter(VALUE klass, ID mid)
402 {
403 char buf[100];
404 const char *mid_name;
405
406 buf[0] = 's'; buf[1] = 'e'; buf[2] = 't';
407 mid_name = rb_id2name(mid);
408
409 buf[3] = toupper(mid_name[0]);
410 buf[4] = '\0';
411 strlcat(buf, &mid_name[1], sizeof buf);
412 strlcat(buf, ":", sizeof buf);
413
414 if (!class_addMethod((Class)klass, sel_registerName(buf),
415 (IMP)rb_objc_kvo_setter_imp, "v@:@")) {
f8a1963 don't show this annoying warning by default
Laurent Sansonetti authored
416 rb_warning("can't register `%s' as an KVO setter on class `%s' "\
ba24a07 better warning
Laurent Sansonetti authored
417 "(method `%s')",
418 mid_name, rb_class2name(klass), buf);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
419 }
420 }
421
422 VALUE
423 rb_mod_objc_ib_outlet(VALUE recv, SEL sel, int argc, VALUE *argv)
424 {
425 int i;
426
427 rb_warn("ib_outlet has been deprecated, please use attr_writer instead");
428
429 for (i = 0; i < argc; i++) {
430 VALUE sym = argv[i];
431
432 Check_Type(sym, T_SYMBOL);
433 rb_objc_define_kvo_setter(recv, SYM2ID(sym));
434 }
435
436 return recv;
437 }
438
b8393dc introduce RubyHash, fix a lot of minor bugs, start cleaning process
Laurent Sansonetti authored
439 static void *__obj_flags; // used as a static key
9c1d230 committing experimental branch content
Laurent Sansonetti authored
440
441 long
442 rb_objc_flag_get_mask(const void *obj)
443 {
444 return (long)rb_objc_get_associative_ref((void *)obj, &__obj_flags);
445 }
446
447 bool
448 rb_objc_flag_check(const void *obj, int flag)
449 {
b8393dc introduce RubyHash, fix a lot of minor bugs, start cleaning process
Laurent Sansonetti authored
450 const long v = rb_objc_flag_get_mask(obj);
451 if (v == 0) {
452 return false;
453 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
454 return (v & flag) == flag;
455 }
456
457 void
458 rb_objc_flag_set(const void *obj, int flag, bool val)
459 {
460 long v = (long)rb_objc_get_associative_ref((void *)obj, &__obj_flags);
461 if (val) {
462 v |= flag;
463 }
464 else {
465 v ^= flag;
466 }
467 rb_objc_set_associative_ref((void *)obj, &__obj_flags, (void *)v);
468 }
469
470 static IMP old_imp_isaForAutonotifying;
471
472 static Class
473 rb_obj_imp_isaForAutonotifying(void *rcv, SEL sel)
474 {
475 long ret_version;
476
1c3636c fixed bugs post KVO
Laurent Sansonetti authored
477 Class ret = ((Class (*)(void *, SEL))old_imp_isaForAutonotifying)(rcv, sel);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
478
1c3636c fixed bugs post KVO
Laurent Sansonetti authored
479 if (ret != NULL && ((ret_version = RCLASS_VERSION(ret)) & RCLASS_KVO_CHECK_DONE) == 0) {
9c1d230 committing experimental branch content
Laurent Sansonetti authored
480 const char *name = class_getName(ret);
481 if (strncmp(name, "NSKVONotifying_", 15) == 0) {
482 Class ret_orig;
483 name += 15;
484 ret_orig = objc_getClass(name);
3c0250d fix for <rdar://problem/7210942> instance variables not visible from wit...
Laurent Sansonetti authored
485 if (ret_orig != NULL) {
486 const long orig_v = RCLASS_VERSION(ret_orig);
487 if ((orig_v & RCLASS_IS_OBJECT_SUBCLASS) == RCLASS_IS_OBJECT_SUBCLASS) {
488 ret_version |= RCLASS_IS_OBJECT_SUBCLASS;
489 }
490 if ((orig_v & RCLASS_IS_RUBY_CLASS) == RCLASS_IS_RUBY_CLASS) {
491 ret_version |= RCLASS_IS_RUBY_CLASS;
492 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
493 }
494 }
1c3636c fixed bugs post KVO
Laurent Sansonetti authored
495 ret_version |= RCLASS_KVO_CHECK_DONE;
9c1d230 committing experimental branch content
Laurent Sansonetti authored
496 RCLASS_SET_VERSION(ret, ret_version);
497 }
498 return ret;
499 }
500
1d49107 now throwing pure objc exceptions from ruby, this way they can be catche...
Laurent Sansonetti authored
501 id
bd7eba3 objc exceptions should now be catchable in ruby
Laurent Sansonetti authored
502 rb_rb2oc_exception(VALUE exc)
1d49107 now throwing pure objc exceptions from ruby, this way they can be catche...
Laurent Sansonetti authored
503 {
504 NSString *name = [NSString stringWithUTF8String:rb_obj_classname(exc)];
7d03eb4 @alloy Use the same message format for printed exceptions everywhere.
alloy authored
505 NSString *reason = (NSString *)rb_format_exception_message(exc);
1d49107 now throwing pure objc exceptions from ruby, this way they can be catche...
Laurent Sansonetti authored
506 NSDictionary *dict = [NSDictionary dictionaryWithObject:(id)exc
507 forKey:@"RubyException"];
508 return [NSException exceptionWithName:name reason:reason userInfo:dict];
509 }
510
bd7eba3 objc exceptions should now be catchable in ruby
Laurent Sansonetti authored
511 VALUE
6a0b646 finally re-commit r4185, apparently the problem is somewhere else
Laurent Sansonetti authored
512 rb_oc2rb_exception(id exc, bool *created)
bd7eba3 objc exceptions should now be catchable in ruby
Laurent Sansonetti authored
513 {
6a0b646 finally re-commit r4185, apparently the problem is somewhere else
Laurent Sansonetti authored
514 VALUE e;
515 id rubyExc;
516
517 rubyExc = [[exc userInfo] objectForKey:@"RubyException"];
518 if (rubyExc == nil) {
519 *created = true;
520
521 char buf[1000];
522 snprintf(buf, sizeof buf, "%s: %s", [[exc name] UTF8String],
523 [[exc reason] UTF8String]);
524 e = rb_exc_new2(rb_eRuntimeError, buf);
525 // Set the backtrace for Obj-C exceptions
526 rb_iv_set(e, "bt", rb_vm_backtrace(0));
527 }
528 else {
529 *created = false;
530 e = (VALUE)rubyExc;
531 }
2a235ef Revert r4165 and fix the issue within MacRuby instead.
Thibault Martin-Lagardette authored
532 return e;
bd7eba3 objc exceptions should now be catchable in ruby
Laurent Sansonetti authored
533 }
534
768bfbb added #%, added remaining NSString primitives
Laurent Sansonetti authored
535 void
536 rb_objc_exception_raise(const char *name, const char *message)
537 {
538 assert(name != NULL && message != NULL);
539 [[NSException exceptionWithName:[NSString stringWithUTF8String:name]
540 reason:[NSString stringWithUTF8String:message] userInfo:nil] raise];
541 }
542
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
543 id
544 rb_objc_numeric2nsnumber(VALUE obj)
545 {
546 if (FIXNUM_P(obj)) {
547 // TODO: this could be optimized in case we can fit the fixnum
548 // into an immediate NSNumber directly.
549 long val = FIX2LONG(obj);
550 CFNumberRef number = CFNumberCreate(NULL, kCFNumberLongType, &val);
551 CFMakeCollectable(number);
552 return (id)number;
553 }
554 if (FIXFLOAT_P(obj)) {
555 double val = NUM2DBL(obj);
556 CFNumberRef number = CFNumberCreate(NULL, kCFNumberDoubleType,
557 &val);
558 CFMakeCollectable(number);
559 return (id)number;
560 }
561 abort();
562 }
563
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
564 static SEL sel_at = 0;
565
3760073 Handle NSDate immediate
Thibault Martin-Lagardette authored
566 VALUE
567 rb_objc_convert_immediate(id obj)
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
568 {
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
569 const bool is_immediate = ((unsigned long)obj & 0x1) == 0x1;
570
571 Class orig_k = object_getClass(obj); // might be an immediate
572 Class k = orig_k;
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
573 do {
574 if (k == (Class)rb_cNSNumber) {
3760073 Handle NSDate immediate
Thibault Martin-Lagardette authored
575 // TODO: this could be optimized in case the object is an immediate.
576 if (CFNumberIsFloatType((CFNumberRef)obj)) {
577 double v = 0;
578 assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberDoubleType, &v));
579 return DOUBLE2NUM(v);
580 }
581 else {
582 long v = 0;
583 assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberLongType, &v));
01965bc @lrz fix truncation issues when dealing with unsigned long long types
lrz authored
584 return LONG2NUM(v);
3760073 Handle NSDate immediate
Thibault Martin-Lagardette authored
585 }
586 }
587 else if (k == (Class)rb_cNSDate) {
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
588 @try {
8ccbe05 @vincentisambart in 32-bit immediate float are very imprecise so to convert NSDate to
vincentisambart authored
589 CFAbsoluteTime time = CFDateGetAbsoluteTime((CFDateRef)obj) + CF_REFERENCE_DATE;
590 #if __LP64__
591 VALUE arg = DBL2NUM(time);
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
592 return rb_vm_call(rb_cTime, sel_at, 1, &arg);
8ccbe05 @vincentisambart in 32-bit immediate float are very imprecise so to convert NSDate to
vincentisambart authored
593 #else
594 // immediate floats have not enough precision in 32-bit
595 // so instead of using Time.at(time in float),
596 // we use Time.at(sec, usec)
597 double integral, fractional;
598 fractional = modf(time, &integral);
599 VALUE args[] = {
600 LONG2NUM((long)integral),
601 LONG2NUM((long)(fractional * 1e6 + 0.5))
602 };
603 return rb_vm_call(rb_cTime, sel_at, 2, args);
604 #endif
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
605 }
606 @catch (NSException *e) {
607 // Some NSDates might return an exception (example: uninitialized objects).
608 break;
609 }
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
610 }
611 k = class_getSuperclass(k);
612 }
613 while (k != NULL);
614
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
615 if (is_immediate) {
616 rb_bug("unknown Objective-C immediate: %p (%s)\n", obj, class_getName(orig_k));
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
617 }
618 return (VALUE)obj;
619 }
620
d40a42f a better fix for ignored selectors, which handle the case where they are...
Laurent Sansonetti authored
621 bool
82cd78b added basic support to define/message ignored selectors (retain & friend...
Laurent Sansonetti authored
622 rb_objc_ignored_sel(SEL sel)
fdb8951 better ignored sel detection
Laurent Sansonetti authored
623 {
d40a42f a better fix for ignored selectors, which handle the case where they are...
Laurent Sansonetti authored
624 return sel == @selector(retain)
625 || sel == @selector(release)
626 || sel == @selector(autorelease)
627 || sel == @selector(retainCount)
628 || sel == @selector(dealloc);
13c85fa force class initialization upon lazy lookup
Laurent Sansonetti authored
629 }
630
2edcd79 make NSObject#== and NSObject#eql? use -[NSObject isEqual:]
Laurent Sansonetti authored
631 bool
632 rb_objc_isEqual(VALUE x, VALUE y)
633 {
634 return [RB2OC(x) isEqual:RB2OC(y)];
635 }
636
13c85fa force class initialization upon lazy lookup
Laurent Sansonetti authored
637 void
638 rb_objc_force_class_initialize(Class klass)
639 {
97c73ac do not auto-initialize classes that are not NSObject-based
Laurent Sansonetti authored
640 // Do not do anything in case the class is not NSObject-based
641 // (likely Proxy).
642 bool ok = false;
643 for (Class k = klass; k != NULL; k = class_getSuperclass(k)) {
644 if (k == (Class)rb_cNSObject) {
645 ok = true;
646 break;
647 }
648 }
649 if (!ok) {
650 return;
651 }
652
13c85fa force class initialization upon lazy lookup
Laurent Sansonetti authored
653 // This forces +initialize to be called.
654 class_getMethodImplementation(klass, @selector(initialize));
fdb8951 better ignored sel detection
Laurent Sansonetti authored
655 }
656
9213dad expose a new API (to be used by a future patch)
Laurent Sansonetti authored
657 size_t
658 rb_objc_type_size(const char *type)
659 {
660 @try {
661 NSUInteger size, align;
662 NSGetSizeAndAlignment(type, &size, &align);
663 return size;
664 }
665 @catch (id ex) {
666 rb_raise(rb_eRuntimeError, "can't get the size of type `%s': %s",
667 type, [[ex description] UTF8String]);
668 }
669 return 0; // never reached
670 }
671
fa47b46 in case we are in a .app with MacRuby.framework embedded inside, relocat...
Laurent Sansonetti authored
672 static NSString *
673 relocated_load_path(NSString *path, NSString *macruby_path)
674 {
f024e51 @lrz when relocating the load path when MacRuby.framework is embedded, make s...
lrz authored
675 // Relocate framework path.
fa47b46 in case we are in a .app with MacRuby.framework embedded inside, relocat...
Laurent Sansonetti authored
676 NSRange r = [path rangeOfString:@"MacRuby.framework"];
677 if (r.location == NSNotFound) {
678 return nil;
679 }
680 r = NSMakeRange(0, r.location + r.length);
f024e51 @lrz when relocating the load path when MacRuby.framework is embedded, make s...
lrz authored
681 path = [path stringByReplacingCharactersInRange:r withString:macruby_path];
682
683 // Since we are using an embedded version of MacRuby, we also need to
684 // not use any version number in the path, as it's stripped out by
685 // macruby_deploy.
686 NSString *version = [NSString stringWithFormat:@"/Versions/%s/",
687 MACRUBY_VERSION];
688 path = [path stringByReplacingOccurrencesOfString:version
689 withString:@"/Versions/Current/"];
690 return path;
fa47b46 in case we are in a .app with MacRuby.framework embedded inside, relocat...
Laurent Sansonetti authored
691 }
692
693 void
694 rb_objc_fix_relocatable_load_path(void)
695 {
696 NSString *path = [[NSBundle mainBundle] privateFrameworksPath];
697 path = [path stringByAppendingPathComponent:@"MacRuby.framework"];
698
699 NSFileManager *fm = [NSFileManager defaultManager];
700 if ([fm fileExistsAtPath:path]) {
701 VALUE ary = rb_vm_load_path();
702 for (long i = 0, count = RARRAY_LEN(ary); i < count; i++) {
703 NSString *p1 = (NSString *)RARRAY_AT(ary, i);
704 NSString *p2 = relocated_load_path(p1, path);
705 if (p2 != nil) {
706 rb_ary_store(ary, i, (VALUE)p2);
707 }
708 }
709 }
710 }
711
9c1d230 committing experimental branch content
Laurent Sansonetti authored
712 void
a3a0414 Xcode MacRuby apps will load the BridgeSupport files of frameworks linke...
Laurent Sansonetti authored
713 rb_objc_load_loaded_frameworks_bridgesupport(void)
714 {
715 #if !defined(MACRUBY_STATIC)
716 for (NSBundle *b in [NSBundle allFrameworks]) {
717 if ([b isLoaded]) {
718 NSString *path = [b bundlePath];
55b12f3 fix calls to -[NSString fileSystemRepresentation] to catch potential exc...
Laurent Sansonetti authored
719 rb_objc_search_and_load_bridge_support(fileSystemPath(path));
a3a0414 Xcode MacRuby apps will load the BridgeSupport files of frameworks linke...
Laurent Sansonetti authored
720 }
721 }
722 #endif
723 }
724
725 void
968a432 fix a bug when sending kvo notifications on immediate objects would caus...
Laurent Sansonetti authored
726 rb_objc_willChangeValueForKey(VALUE obj, NSString *key)
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
727 {
968a432 fix a bug when sending kvo notifications on immediate objects would caus...
Laurent Sansonetti authored
728 if (!SPECIAL_CONST_P(obj)) {
729 [(id)obj willChangeValueForKey:key];
730 }
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
731 }
732
733 void
968a432 fix a bug when sending kvo notifications on immediate objects would caus...
Laurent Sansonetti authored
734 rb_objc_didChangeValueForKey(VALUE obj, NSString *key)
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
735 {
968a432 fix a bug when sending kvo notifications on immediate objects would caus...
Laurent Sansonetti authored
736 if (!SPECIAL_CONST_P(obj)) {
737 [(id)obj didChangeValueForKey:key];
738 }
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
739 }
740
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
741 static VALUE
742 rb_objc_load_plist(VALUE recv, SEL sel, VALUE str)
743 {
744 StringValue(str);
745 VALUE bstr = rb_str_bstr(str);
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
746 NSData *data = [NSData dataWithBytes:rb_bstr_bytes(bstr)
747 length:rb_bstr_length(bstr)];
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
748 NSError *err = nil;
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
749 id plist = [NSPropertyListSerialization propertyListWithData:data options:0
750 format:NULL error:&err];
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
751 if (plist == nil) {
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
752 rb_raise(rb_eArgError, "error loading property list: '%s'",
753 [[err localizedDescription] UTF8String]);
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
754 }
755 return OC2RB(plist);
756 }
757
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
758 extern VALUE rb_cNSDate;
759
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
760 static VALUE
761 rb_objc_to_plist(VALUE recv, SEL sel)
762 {
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
763 switch (TYPE(recv)) {
764 case T_STRING:
765 case T_FIXNUM:
766 case T_FLOAT:
767 case T_BIGNUM:
768 case T_HASH:
769 case T_ARRAY:
770 case T_TRUE:
771 case T_FALSE:
772 break;
773
774 default:
775 if (!rb_obj_is_kind_of(recv, rb_cNSDate)) {
776 rb_raise(rb_eArgError,
777 "object of class '%s' cannot be serialized to " \
778 "property-list format",
779 rb_obj_classname(recv));
780 }
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
781 }
9f35b9c added NSDate support in #to_plist + reformatted code
Laurent Sansonetti authored
782
783 id objc_obj = RB2OC(recv);
784 NSError *err = nil;
785 NSData *data = [NSPropertyListSerialization dataWithPropertyList:objc_obj
786 format:NSPropertyListXMLFormat_v1_0 options:0 error:&err];
787 if (data == nil) {
788 rb_raise(rb_eArgError, "error serializing property list: '%s'",
789 [[err localizedDescription] UTF8String]);
790 }
791 const uint8_t* bytes = [data bytes];
792 const size_t len = [data length];
793 return rb_bstr_new_with_data(bytes, len);
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
794 }
795
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
796 static bool
797 implementsProtocolMethods(Protocol *p, Class klass, bool instanceMethods)
798 {
799 unsigned int count = 0;
800 struct objc_method_description *list =
801 protocol_copyMethodDescriptionList(p, true, instanceMethods, &count);
802 if (list != NULL) {
803 bool success = true;
804 for (unsigned int i = 0; i < count; i++) {
805 SEL msel = list[i].name;
806 Method m;
807 if (instanceMethods) {
808 m = class_getInstanceMethod(klass, msel);
809 }
810 else {
811 m = class_getClassMethod(klass, msel);
812 }
813 if (m == NULL) {
814 success = false;
815 break;
816 }
817 }
818 free(list);
819 if (success) {
820 return true;
821 }
822 return false;
823 }
824 return true;
825 }
826
827 static bool
828 conformsToProtocol(Class klass, Protocol *p)
829 {
830 if (implementsProtocolMethods(p, klass, true)
831 && implementsProtocolMethods(p, klass, false)) {
832 unsigned int count = 0;
4b7b568 @lrz fix a compilation warning on the bleeding edge
lrz authored
833 Protocol **list = (Protocol **)protocol_copyProtocolList(p, &count);
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
834 bool success = true;
835 for (unsigned int i = 0; i < count; i++) {
836 if (!conformsToProtocol(klass, list[i])) {
837 success = false;
838 break;
839 }
840 }
841 free(list);
842 return success;
843 }
844 return false;
845 }
846
847 static bool
848 conformsToProtocolAndAncestors(void *self, SEL sel, Class klass,
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
849 void *protocol)
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
850 {
851 if (protocol != NULL) {
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
852 for (Class k = klass; k != NULL; k = class_getSuperclass(k)) {
853 if (class_conformsToProtocol(k, protocol)) {
854 return true;
855 }
856 }
857
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
858 Protocol *p = (Protocol *)protocol;
859 if (conformsToProtocol(klass, p)) {
860 class_addProtocol(klass, p);
861 return true;
862 }
863 }
864 return false;
865 }
866
867 static bool
868 robj_conformsToProtocol(void *self, SEL sel, void *protocol)
869 {
870 return conformsToProtocolAndAncestors(self, sel, object_getClass(self),
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
871 protocol);
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
872 }
873
874 static bool
875 robj_conformsToProtocol_m(void *self, SEL sel, void *protocol)
876 {
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
877 return conformsToProtocolAndAncestors(self, sel, (Class)self, protocol);
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
878 }
879
880 static id
881 robj_performSelector(void *self, SEL sel, SEL msg)
882 {
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
883 return RB2OC(rb_vm_call(OC2RB(self), msg, 0, NULL));
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
884 }
885
886 static id
887 robj_performSelectorWithObject(void *self, SEL sel, SEL msg, void *arg)
888 {
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
889 VALUE rarg = OC2RB(arg);
890 return RB2OC(rb_vm_call(OC2RB(self), msg, 1, &rarg));
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
891 }
892
893 static id
894 robj_performSelectorWithObjectWithObject(void *self, SEL sel, SEL msg,
895 void *arg1, void *arg2)
896 {
0e35a34 move the conformsToProtocol: and performSelector: custom methods on dire...
Laurent Sansonetti authored
897 VALUE rarg[2] = { OC2RB(arg1), OC2RB(arg2) };
898 return RB2OC(rb_vm_call(OC2RB(self), msg, 2, rarg));
899 }
900
901 void
902 rb_objc_install_NSObject_special_methods(Class k)
903 {
904 SEL sel = sel_registerName("conformsToProtocol:");
905 rb_objc_install_method(k, sel, (IMP)robj_conformsToProtocol);
906 rb_objc_install_method(*(Class *)k, sel, (IMP)robj_conformsToProtocol_m);
907
908 rb_objc_install_method2(k, "performSelector:", (IMP)robj_performSelector);
909 rb_objc_install_method2(k, "performSelector:withObject:",
910 (IMP)robj_performSelectorWithObject);
911 rb_objc_install_method2(k, "performSelector:withObject:withObject:",
912 (IMP)robj_performSelectorWithObjectWithObject);
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
913 }
914
002ed5d now compile some of the VM primitives into bitcode that will be added to...
Laurent Sansonetti authored
915 void
9c1d230 committing experimental branch content
Laurent Sansonetti authored
916 Init_ObjC(void)
917 {
b78bd9e better/faster handling of NSDates
Laurent Sansonetti authored
918 sel_at = sel_registerName("at:");
919
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
920 rb_objc_define_module_function(rb_mKernel, "load_bridge_support_file",
921 rb_objc_load_bs, 1);
922 rb_objc_define_module_function(rb_mKernel, "load_plist",
923 rb_objc_load_plist, 1);
971d78e Add Object#to_plist and Kernel#load_plist for property list manipulation...
Patrick Thomson authored
924
925 rb_objc_define_method(rb_cObject, "to_plist", rb_objc_to_plist, 0);
9c1d230 committing experimental branch content
Laurent Sansonetti authored
926
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
927 // Overwrite -[NSKeyValueUnnestedProperty isaForAutonotifying].
97c73ac do not auto-initialize classes that are not NSObject-based
Laurent Sansonetti authored
928 Class k = objc_getClass("NSKeyValueUnnestedProperty");
929 assert(k != NULL);
930 Method m = class_getInstanceMethod(k, @selector(isaForAutonotifying));
9c1d230 committing experimental branch content
Laurent Sansonetti authored
931 assert(m != NULL);
932 old_imp_isaForAutonotifying = method_getImplementation(m);
933 method_setImplementation(m, (IMP)rb_obj_imp_isaForAutonotifying);
0cde2c8 mark Foundation as multithreaded
Laurent Sansonetti authored
934
935 // Mark Foundation as multithreaded.
5930de6 make performSelector: and friends dispatch pure-ruby methods properly
Laurent Sansonetti authored
936 [NSThread detachNewThreadSelector:@selector(self) toTarget:[NSThread class]
937 withObject:nil];
9c1d230 committing experimental branch content
Laurent Sansonetti authored
938 }
939
940 @interface Protocol
941 @end
942
943 @implementation Protocol (MRFindProtocol)
e3ee11d Change `+protocolWithName` signature
Thibault Martin-Lagardette authored
944 + (Protocol *)protocolWithName:(NSString *)name
9c1d230 committing experimental branch content
Laurent Sansonetti authored
945 {
e3ee11d Change `+protocolWithName` signature
Thibault Martin-Lagardette authored
946 return (Protocol *)objc_getProtocol([name UTF8String]);
947 }
9c1d230 committing experimental branch content
Laurent Sansonetti authored
948 @end
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
949
950 #if !defined(MACRUBY_STATIC)
951 static NSString *
952 get_type(NSXMLElement *elem)
953 {
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
954 NSXMLNode *node = nil;
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
955 #if __LP64__
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
956 node = [elem attributeForName:@"type64"];
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
957 #endif
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
958 if (node == nil) {
959 node = [elem attributeForName:@"type"];
960 if (node == nil) {
961 return nil;
962 }
963 }
964 return [node stringValue];
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
965 }
966
967 static void
968 add_stub_types(NSXMLElement *elem,
969 void (*add_stub_types_cb)(SEL, const char *, bool, void *),
970 void *ctx,
971 bool is_objc)
972 {
973 NSXMLNode *name = [elem attributeForName:is_objc
974 ? @"selector" : @"name"];
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
975 if (name == nil) {
976 return;
977 }
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
978 NSArray *ary = [elem elementsForName:@"retval"];
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
979 if ([ary count] != 1) {
980 return;
981 }
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
982 NSXMLElement *retval = [ary objectAtIndex:0];
983 NSMutableString *types = [NSMutableString new];
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
984 NSString *type = get_type(retval);
985 if (type == nil) {
986 return;
987 }
988 [types appendString:type];
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
989 if (is_objc) {
990 [types appendString:@"@:"]; // self, sel
991 }
992 ary = [elem elementsForName:@"arg"];
993 for (NSXMLElement *a in ary) {
7ff9fb0 more relax parser (10.6 builtin files are less good)
Laurent Sansonetti authored
994 type = get_type(a);
995 if (type == nil) {
996 return;
997 }
998 [types appendString:type];
9d1b612 aot: precompiling BridgeSupport metadata (work in progress)
Laurent Sansonetti authored
999 }
1000 NSString *sel_str = [name stringValue];
1001 if (!is_objc && [ary count] > 0) {
1002 sel_str = [sel_str stringByAppendingString:@":"];
1003 }
1004 SEL sel = sel_registerName([sel_str UTF8String]);
1005 add_stub_types_cb(sel, [types UTF8String], is_objc, ctx);
1006 }
1007
1008 void
1009 rb_vm_parse_bs_full_file(const char *path,
1010 void (*add_stub_types_cb)(SEL, const char *, bool, void *),
1011 void *ctx)
1012 {
1013 NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:path]];
1014 NSError *err = nil;
1015 NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL: url
1016 options: 0 error: &err];
1017 if (doc == nil) {
1018 NSLog(@"can't open BridgeSupport full file at path `%s': %@",
1019 path, err);
1020 exit(1);
1021 }
1022 NSXMLElement *root = [doc rootElement];
1023
1024 for (NSXMLElement *k in [root elementsForName:@"class"]) {
1025 for (NSXMLElement *m in [k elementsForName:@"method"]) {
1026 add_stub_types(m, add_stub_types_cb, ctx, true);
1027 }
1028 }
1029 for (NSXMLElement *f in [root elementsForName:@"function"]) {
1030 add_stub_types(f, add_stub_types_cb, ctx, false);
1031 }
1032 }
1033 #endif
Something went wrong with that request. Please try again.