1/*
2 * Copyright (c) 2006-2008, The RubyCocoa Project.
3 * Copyright (c) 2001-2006, FUJIMOTO Hisakuni.
4 * All Rights Reserved.
5 *
6 * RubyCocoa is free software, covered under either the Ruby's license or the
7 * LGPL. See the COPYRIGHT file for more information.
8 */
9
10#import "osx_ruby.h"
11#import "ocdata_conv.h"
12#import "mdl_osxobjc.h"
13#import <Foundation/Foundation.h>
14#import <string.h>
15#import <stdlib.h>
16#import <stdarg.h>
17#import <objc/objc-runtime.h>
18#import "BridgeSupport.h"
19#import "internal_macros.h"
20#import "ocexception.h"
21#import "objc_compat.h"
22#import <sys/mman.h>
23
24#if __LP64__
25/* FIXME */
26# define OCM_AUTO_REGISTER 0
27#else
28# define OCM_AUTO_REGISTER 1
29#endif
30
31static VALUE _mObjWrapper = Qnil;
32static VALUE _mClsWrapper = Qnil;
33
34static VALUE wrapper_ocm_send(int argc, VALUE* argv, VALUE rcv);
35
36#define OBJWRP_LOG(fmt, args...) DLOG("OBJWRP", fmt, ##args)
37
38struct _ocm_retain_context {
39  VALUE rcv;
40  SEL selector;
41};
42
43static void
44ocm_retain_arg_if_necessary (VALUE result, BOOL is_result, void *context)
45{
46  volatile VALUE rcv = ((struct _ocm_retain_context *)context)->rcv;
47  SEL selector = ((struct _ocm_retain_context *)context)->selector;
48
49  // Retain if necessary the returned ObjC value unless it was generated
50  // by "alloc/allocWithZone/new/copy/mutableCopy".
51  // Some classes may always return a static dummy object (placeholder) for
52  // every [-alloc], so we shouldn't release the return value of these
53  // messages.
54  if (!NIL_P(result) && rb_obj_is_kind_of(result, objid_s_class()) == Qtrue) {
55    if (!OBJCID_DATA_PTR(result)->retained
56        && selector != @selector(alloc)
57        && selector != @selector(allocWithZone:)
58        && selector != @selector(new)
59        && selector != @selector(copy)
60        && selector != @selector(mutableCopy)) {
61
62      if (!is_result
63          || NIL_P(rcv)
64          || strncmp((const char *)selector, "init", 4) != 0
65          || OBJCID_ID(rcv) == OBJCID_ID(result)
66          || !OBJCID_DATA_PTR(rcv)->retained) {
67
68        OBJWRP_LOG("retaining %p", OBJCID_ID(result));
69        [OBJCID_ID(result) retain];
70      }
71    }
72    // We assume that the object is retained at that point.
73    OBJCID_DATA_PTR(result)->retained = YES;
74    if (selector != @selector(alloc) && selector != @selector(allocWithZone:)) {
75      OBJCID_DATA_PTR(result)->can_be_released = YES;
76    }
77    // FIXME: 10.6 NSUndoManager#prepareWithInvocationTarget: raises the
78    // following exception:
79    // ----
80    // uncaught exception 'NSInternalInconsistencyException', reason:
81    // 'forwardInvocation:: NSUndoManager 0x*** received forwarded invocation
82    // while invocation target is nil. Call prepareWithInvocationTarget:
83    // before invoking respondsToSelector:'
84    if (IS_UNDOPROXY(OBJCID_ID(result))) {
85      return; // do not call performSelector:
86    }
87    // Objects that come from an NSObject-based class defined in Ruby have a
88    // slave object as an instance variable that serves as the message proxy.
89    // However, this RBObject retains the Ruby instance by default, which isn't
90    // what we want, because this is a retain circle, and both objects will
91    // leak. So we manually release the Ruby object from the slave, so that
92    // when the Ruby object will be collected by the Ruby GC, the ObjC object
93    // will be properly auto-released.
94    //
95    // We only do this magic for objects that are explicitely allocated from
96    // Ruby.
97    if ([OBJCID_ID(result) respondsToSelector:@selector(__trackSlaveRubyObject)]) {
98      [OBJCID_ID(result) performSelector:@selector(__trackSlaveRubyObject)];
99    }
100  }
101}
102
103struct ocm_closure_userdata
104{
105  VALUE mname;
106  VALUE is_predicate;
107};
108
109static void
110ocm_closure_handler(ffi_cif *cif, void *resp, void **args, void *userdata)
111{
112  VALUE rcv, mname, is_predicate;
113  volatile VALUE argv;
114
115  OBJWRP_LOG("ocm_closure_handler ...");
116
117  rcv = (*(VALUE **)args)[0];
118  argv = (*(VALUE **)args)[1];
119  mname = ((struct ocm_closure_userdata *)userdata)->mname;
120  is_predicate = ((struct ocm_closure_userdata *)userdata)->is_predicate;
121
122  rb_ary_unshift(argv, is_predicate);
123  rb_ary_unshift(argv, Qnil);
124  rb_ary_unshift(argv, mname);
125
126  *(VALUE *)resp = wrapper_ocm_send(RARRAY(argv)->len, RARRAY(argv)->ptr, rcv);
127
128  OBJWRP_LOG("ocm_closure_handler ok");
129}
130
131static void *
132ocm_ffi_closure(VALUE mname, VALUE is_predicate)
133{
134  static ffi_cif *cif = NULL;
135  ffi_closure *closure;
136  struct ocm_closure_userdata *userdata;
137
138  if (cif == NULL) {
139    static ffi_type *args[3];
140
141    cif = (ffi_cif *)malloc(sizeof(ffi_cif));
142    ASSERT_ALLOC(cif);
143
144    args[0] = &ffi_type_pointer;
145    args[1] = &ffi_type_pointer;
146    args[2] = NULL;
147
148    if (ffi_prep_cif(cif, FFI_DEFAULT_ABI, 2, &ffi_type_pointer, args)
149        != FFI_OK) {
150      free(cif);
151      return NULL;
152    }
153  }
154
155  // Allocate a page to hold the closure with read and write permissions.
156  closure = mmap(NULL, sizeof(ffi_closure), PROT_READ | PROT_WRITE,
157	  MAP_ANON | MAP_PRIVATE, -1, 0);
158  if (closure == (void *)-1) {
159    return NULL;
160  }
161
162  userdata = (struct ocm_closure_userdata *)malloc(
163    sizeof(struct ocm_closure_userdata));
164  ASSERT_ALLOC(userdata);
165
166  userdata->mname = mname;
167  userdata->is_predicate = is_predicate;
168
169  if (ffi_prep_closure(closure, cif, ocm_closure_handler, userdata)
170      != FFI_OK)
171    return NULL;
172
173  if (mprotect(closure, sizeof(ffi_closure), PROT_READ | PROT_EXEC) == -1) {
174    return NULL;
175  }
176
177  return closure;
178}
179
180static BOOL ignore_ns_override = NO;
181
182static VALUE
183wrapper_ignore_ns_override (VALUE rcv)
184{
185  return ignore_ns_override ? Qtrue : Qfalse;
186}
187
188static VALUE
189wrapper_ignore_ns_override_set (VALUE rcv, VALUE val)
190{
191  ignore_ns_override = RTEST(val);
192  return val;
193}
194
195#if OCM_AUTO_REGISTER
196static void
197ocm_register(Class klass, VALUE oc_mname, VALUE rb_mname, VALUE is_predicate,
198  SEL selector, BOOL is_class_method)
199{
200  Class c;
201  Method (*getMethod)(Class, SEL);
202  VALUE rclass;
203  RB_ID rclass_id;
204  void *closure;
205  const char *rb_mname_str;
206
207  // should not register methods on proxy classes
208  if ([klass isKindOfClass:[NSProxy class]]) {
209    return;
210  }
211
212  // Let's locate the original class where the method is defined.
213  getMethod = is_class_method ? class_getClassMethod : class_getInstanceMethod;
214  while ((c = class_getSuperclass(klass)) != NULL
215         && (*getMethod)(c, selector) != NULL) {
216    klass = c;
217  }
218
219  // Find the class.
220  rclass_id = rb_intern(class_getName(klass));
221  if (!rb_const_defined(osx_s_module(), rclass_id)
222      || (rclass = rb_const_get(osx_s_module(), rclass_id)) == Qnil) {
223    OBJWRP_LOG("cannot register Ruby method (problem when getting class)");
224    return;
225  }
226
227  // Create the closure.
228  closure = ocm_ffi_closure(oc_mname, is_predicate);
229  if (closure == NULL) {
230    OBJWRP_LOG("cannot register Ruby method (problem when creating closure)");
231    return;
232  }
233
234  if (TYPE(rb_mname) == T_SYMBOL) {
235    rb_mname_str = rb_id2name(SYM2ID(rb_mname));
236  } else {
237    rb_mname_str = NULL;
238  }
239
240  if (rb_mname_str == NULL || strlen(rb_mname_str) <= 0) {
241    OBJWRP_LOG("cannot register Ruby %s method `%s' on `%s' "
242      "(problem when getting method name)",
243      is_class_method ? "class" : "instance",
244      RSTRING(rb_inspect(rb_mname))->ptr, rb_class2name(rclass));
245    return;
246  }
247
248  OBJWRP_LOG("registering Ruby %s method `%s' on `%s'",
249    is_class_method ? "class" : "instance", rb_mname_str,
250    rb_class2name(rclass));
251
252  // Map.
253  ignore_ns_override = YES;
254  if (is_class_method)
255    rb_define_singleton_method(rclass, rb_mname_str, closure, -2);
256  else
257    rb_define_method(rclass, rb_mname_str, closure, -2);
258  ignore_ns_override = NO;
259
260  // This is a dirty trick to make sure the mname object won't be collected.
261  {
262    RB_ID   mname_id;
263    VALUE   ary;
264
265    mname_id = rb_intern("@__mnames__");
266    if (rb_ivar_defined(rclass, mname_id) == Qtrue) {
267      ary = rb_ivar_get(rclass, mname_id);
268    }
269    else {
270      ary = rb_ary_new();
271      rb_ivar_set(rclass, mname_id, ary);
272    }
273    rb_ary_push(ary, oc_mname);
274  }
275
276  OBJWRP_LOG("registered Ruby %s method `%s' on `%s'",
277    is_class_method ? "class" : "instance", rb_mname_str,
278    rb_class2name(rclass));
279}
280#endif
281
282static VALUE
283ocm_send(int argc, VALUE* argv, VALUE rcv, VALUE* result)
284{
285  SEL                   selector;
286  NSAutoreleasePool *   pool;
287  id                    oc_rcv;
288  Class                 klass;
289  Method                method;
290  IMP                   imp;
291  NSMethodSignature *   methodSignature;
292  unsigned              numberOfArguments;
293  unsigned              expected_argc;
294  char *                methodReturnType;
295  char **               argumentsTypes;
296  BOOL                  is_class_method;
297  struct bsMethod *     bs_method;
298  ffi_type **           arg_types;
299  void **               arg_values;
300  VALUE                 exception;
301
302  if (argc < 3)
303    return Qfalse;
304
305  pool = [[NSAutoreleasePool alloc] init];
306
307  selector = rbobj_to_nssel(argv[0]);
308  exception = Qnil;
309
310  methodReturnType = NULL;
311  argumentsTypes = NULL;
312
313  if (!rbobj_to_nsobj(rcv, &oc_rcv) || oc_rcv == nil) {
314    exception = rb_err_new(ocmsgsend_err_class(), "Can't get Objective-C object in %s", RSTRING(rb_inspect(rcv))->ptr);
315    goto bails;
316  }
317
318  klass = object_getClass(oc_rcv);
319  method = class_getInstanceMethod(klass, selector);
320  if (method == NULL) {
321    // If we can't get the method signature via the ObjC runtime, let's try the NSObject API,
322    // as the target class may override the invocation dispatching methods (as NSUndoManager).
323    methodSignature = [oc_rcv methodSignatureForSelector:selector];
324    if (methodSignature == nil) {
325      exception = rb_err_new(ocmsgsend_err_class(), "Can't get Objective-C method signature for selector '%s' of receiver %s", (char *) selector, RSTRING(rb_inspect(rcv))->ptr);
326      goto bails;
327    }
328    // Let's use the regular message dispatcher.
329    imp = objc_msgSend;
330  }
331  else {
332    methodSignature = nil;
333    imp = method_getImplementation(method);
334  }
335
336  decode_method_encoding(method != NULL ? method_getTypeEncoding(method) : NULL, methodSignature, &numberOfArguments, &methodReturnType, &argumentsTypes, YES);
337
338  // force predicate conversion if required
339  if ((*methodReturnType == _C_UCHR || *methodReturnType == _C_CHR)
340      && RTEST(argv[2]))
341    *methodReturnType = 'B'; // _C_BOOL
342
343  struct _ocm_retain_context context = { rcv, selector };
344
345  is_class_method = TYPE(rcv) == T_CLASS;
346  if (is_class_method)
347    klass = (Class)oc_rcv;
348
349#if OCM_AUTO_REGISTER
350  if (!NIL_P(argv[1])
351      && !rb_obj_is_kind_of(rcv, ocobj_s_class())
352      && method != NULL
353      && rb_respond_to(rcv, SYM2ID(argv[1])) == 0)
354    ocm_register(klass, argv[0], argv[1], argv[2], selector, is_class_method);
355#endif
356
357  argc--; // skip objc method name
358  argv++;
359  argc--; // skip ruby method name
360  argv++;
361  argc--; // skip is predicate flag
362  argv++;
363
364  OBJWRP_LOG("ocm_send (%s%c%s): args_count=%d ret_type=%s", class_getName(klass), is_class_method ? '.' : '#', selector, argc, methodReturnType);
365
366  // Easy case: a method returning ID (or nothing) _and_ without argument.
367  // We don't need libffi here, we can just call it (faster).
368  if (numberOfArguments == 0
369      && (*methodReturnType == _C_VOID || *methodReturnType == _C_ID || *methodReturnType == _C_CLASS)) {
370
371    id  val;
372
373    exception = Qnil;
374    @try {
375      OBJWRP_LOG("direct call easy method %s imp %p", (const char *)selector, imp);
376      val = (*imp)(oc_rcv, selector);
377    }
378    @catch (id oc_exception) {
379      OBJWRP_LOG("got objc exception '%@' -- forwarding...", oc_exception);
380      exception = oc_err_new(oc_exception);
381    }
382
383    if (NIL_P(exception)) {
384      if (*methodReturnType != _C_VOID) {
385        /* Theoretically, ObjC objects should be removed from the oc2rb
386           cache upon dealloc, but it is possible to lose some of them when
387           they are allocated within a thread that is directly killed. */
388        if (selector == @selector(alloc))
389          remove_from_oc2rb_cache(val);
390
391        OBJWRP_LOG("got return value %p", val);
392        if (!ocdata_to_rbobj(rcv, methodReturnType, (const void *)&val, result, NO)) {
393          exception = rb_err_new(ocdataconv_err_class(), "Cannot convert the result as '%s' to Ruby", methodReturnType);
394        }
395        else {
396          ocm_retain_arg_if_necessary(*result, YES, &context);
397        }
398      }
399      else {
400        *result = Qnil;
401      }
402    }
403    else {
404      *result = Qnil;
405    }
406    goto success;
407  }
408
409  expected_argc = numberOfArguments;
410
411  bs_method = find_bs_method(klass, (const char *) selector, is_class_method);
412  if (bs_method != NULL) {
413    OBJWRP_LOG("found metadata description\n");
414    if (bs_method->ignore) {
415      exception = rb_err_new(rb_eRuntimeError, "Method '%s' is not supported (suggested alternative: '%s')", selector, bs_method->suggestion != NULL ? bs_method->suggestion : "n/a");
416      goto bails;
417    }
418    if (bs_method->is_variadic && argc > numberOfArguments) {
419      unsigned i;
420      VALUE format_str;
421
422      expected_argc = argc;
423      format_str = Qnil;
424      argumentsTypes = (char **)realloc(argumentsTypes, sizeof(char *) * argc);
425      ASSERT_ALLOC(argumentsTypes);
426
427      for (i = 0; i < bs_method->argc; i++) {
428        struct bsArg *bs_arg = &bs_method->argv[i];
429        if (bs_arg->printf_format) {
430          assert(bs_arg->index < argc);
431          format_str = argv[bs_arg->index];
432        }
433      }
434
435      if (NIL_P(format_str)) {
436        for (i = numberOfArguments; i < argc; i++)
437          argumentsTypes[i] = "@"; // _C_ID
438      }
439      else {
440        set_octypes_for_format_str(&argumentsTypes[numberOfArguments],
441          argc - numberOfArguments, StringValuePtr(format_str));
442      }
443    }
444  }
445
446  arg_types = (ffi_type **) alloca((expected_argc + 3) * sizeof(ffi_type *));
447  ASSERT_ALLOC(arg_types);
448  arg_values = (void **) alloca((expected_argc + 3) * sizeof(void *));
449  ASSERT_ALLOC(arg_values);
450
451  arg_types[0] = &ffi_type_pointer;
452  arg_types[1] = &ffi_type_pointer;
453  arg_values[0] = &oc_rcv;
454  arg_values[1] = &selector;
455
456  memset(arg_types + 2, 0, (expected_argc + 1) * sizeof(ffi_type *));
457  memset(arg_values + 2, 0, (expected_argc + 1) * sizeof(void *));
458
459  exception = rb_ffi_dispatch(
460    (struct bsCallEntry *)bs_method,
461    argumentsTypes,
462    expected_argc,
463    argc,
464    2,
465    argv,
466    arg_types,
467    arg_values,
468    methodReturnType,
469    imp,
470    ocm_retain_arg_if_necessary,
471    &context,
472    result);
473
474success:
475  OBJWRP_LOG("ocm_send (%s) done%s", (const char *)selector, NIL_P(exception) ? "" : " with exception");
476
477bails:
478  if (methodReturnType != NULL)
479    free(methodReturnType);
480  if (argumentsTypes != NULL) {
481    unsigned i;
482    for (i = 0; i < numberOfArguments; i++)
483      free(argumentsTypes[i]);
484    free(argumentsTypes);
485  }
486
487  [pool release];
488
489  return exception;
490}
491
492/*************************************************/
493
494static VALUE
495wrapper_ocm_responds_p(VALUE rcv, VALUE sel)
496{
497  id oc_rcv;
498  SEL oc_sel = rbobj_to_nssel(sel);
499  rbobj_to_nsobj(rcv, &oc_rcv);
500  return [oc_rcv respondsToSelector: oc_sel] ? Qtrue : Qfalse;
501}
502
503#if 0
504// Disabled, because we don't have a working implementation for systems
505// equal or below than Tiger.
506static VALUE
507wrapper_ocm_conforms_p(VALUE rcv, VALUE name)
508{
509  Protocol *protocol = objc_getProtocol(StringValuePtr(name));
510  if (protocol == NULL)
511    rb_raise(rb_eArgError, "Invalid protocol name `%s'", StringValuePtr(name));
512  return class_conformsToProtocol(rbobj_get_ocid(rcv), protocol) ? Qtrue : Qfalse;
513}
514#endif
515
516static VALUE
517wrapper_ocm_send(int argc, VALUE* argv, VALUE rcv)
518{
519  VALUE result;
520  VALUE exc;
521  exc = ocm_send(argc, argv, rcv, &result);
522  if (!NIL_P(exc)) {
523    if (exc == Qfalse)
524      exc = rb_err_new(ocmsgsend_err_class(), "cannot forward message.");
525    rb_exc_raise (exc);
526  }
527  return result;
528}
529
530static VALUE
531wrapper_to_s (VALUE rcv)
532{
533  VALUE ret;
534  id oc_rcv;
535  id pool;
536
537  rbobj_to_nsobj(rcv, &oc_rcv);
538  pool = [[NSAutoreleasePool alloc] init];
539  oc_rcv = [oc_rcv description];
540  ret = ocstr_to_rbstr(oc_rcv);
541  [pool release];
542  return ret;
543}
544
545static void
546_ary_push_objc_methods (VALUE ary, Class cls, int recur)
547{
548  Class superclass = class_getSuperclass(cls);
549#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
550  Method *methods;
551  unsigned int i, count;
552  methods = class_copyMethodList(cls, &count);
553  for (i = 0; i < count; i++)
554    rb_ary_push(ary, rb_str_new2((const char *)method_getName(methods[i])));
555  free(methods);
556#else
557  void* iterator = NULL;
558  struct objc_method_list* list;
559
560  while (list = class_nextMethodList(cls, &iterator)) {
561    int i;
562    struct objc_method* methods = list->method_list;
563
564    for (i = 0; i < list->method_count; i++) {
565      rb_ary_push (ary, rb_str_new2((const char*)(methods[i].method_name)));
566    }
567  }
568#endif
569
570  if (recur && superclass != NULL && !class_isMetaClass(cls))
571    _ary_push_objc_methods (ary, superclass, recur);
572  rb_funcall(ary, rb_intern("uniq!"), 0);
573}
574
575static VALUE
576wrapper_objc_methods (VALUE rcv)
577{
578  VALUE ary;
579  id oc_rcv;
580
581  ary = rb_ary_new();
582  rbobj_to_nsobj(rcv, &oc_rcv);
583  _ary_push_objc_methods (ary, oc_rcv->isa, 1);
584  return ary;
585}
586
587static VALUE
588wrapper_objc_instance_methods (int argc, VALUE* argv, VALUE rcv)
589{
590  VALUE ary;
591  id oc_rcv;
592  int recur;
593
594  recur = (argc == 0) ? 1 : RTEST(argv[0]);
595  ary = rb_ary_new();
596  rbobj_to_nsobj(rcv, &oc_rcv);
597  _ary_push_objc_methods (ary, oc_rcv, recur);
598  return ary;
599}
600
601static VALUE
602wrapper_objc_class_methods (int argc, VALUE* argv, VALUE rcv)
603{
604  VALUE ary;
605  id oc_rcv;
606  int recur;
607
608  recur = (argc == 0) ? 1 : RTEST(argv[0]);
609  ary = rb_ary_new();
610  rbobj_to_nsobj(rcv, &oc_rcv);
611  _ary_push_objc_methods (ary, oc_rcv->isa, recur);
612  return ary;
613}
614
615static const char*
616_objc_method_type (Class cls, const char* name)
617{
618  Method method;
619
620  method = class_getInstanceMethod(cls, sel_registerName(name));
621  if (!method)
622    return NULL;
623  return method_getTypeEncoding(method);
624}
625
626static VALUE
627_name_to_selstr (VALUE name)
628{
629  VALUE re;
630  const char* patstr = "([^^])_";
631  const char* repstr = "\\1:";
632
633  name = rb_obj_as_string (name);
634  re = rb_reg_new (patstr, strlen(patstr), 0);
635  rb_funcall (name, rb_intern("gsub!"), 2, re, rb_str_new2(repstr));
636  return name;
637}
638
639static VALUE
640wrapper_objc_method_type (VALUE rcv, VALUE name)
641{
642  id oc_rcv;
643  const char* str;
644
645  rbobj_to_nsobj(rcv, &oc_rcv);
646  name = _name_to_selstr (name);
647  str = _objc_method_type (oc_rcv->isa, StringValuePtr(name));
648  if (str == NULL) return Qnil;
649  return rb_str_new2(str);
650}
651
652static VALUE
653wrapper_objc_instance_method_type (VALUE rcv, VALUE name)
654{
655  id oc_rcv;
656  const char* str;
657
658  rbobj_to_nsobj(rcv, &oc_rcv);
659  name = _name_to_selstr (name);
660  str = _objc_method_type (oc_rcv, StringValuePtr(name));
661  if (str == NULL) return Qnil;
662  return rb_str_new2(str);
663}
664
665static VALUE
666wrapper_objc_class_method_type (VALUE rcv, VALUE name)
667{
668  id oc_rcv;
669  const char* str;
670
671  rbobj_to_nsobj(rcv, &oc_rcv);
672  name = _name_to_selstr (name);
673  str = _objc_method_type (oc_rcv->isa, StringValuePtr(name));
674  if (str == NULL) return Qnil;
675  return rb_str_new2(str);
676}
677
678
679static id
680_objc_alias_method (Class klass, VALUE new, VALUE old)
681{
682  Method me;
683  SEL new_name;
684  SEL old_name;
685
686  old_name = rbobj_to_nssel(old);
687  new_name = rbobj_to_nssel(new);
688  me = class_getInstanceMethod(klass, old_name);
689
690  // warn if trying to alias a method that isn't a member of the specified class
691  if (me == NULL)
692    rb_raise(rb_eRuntimeError, "could not alias '%s' for '%s' to class '%s': Objective-C cannot find it in the class", (char *)new_name, (char *)old_name, class_getName(klass));
693
694  class_addMethod(klass, new_name, method_getImplementation(me), method_getTypeEncoding(me));
695
696  return nil;
697}
698
699static VALUE
700wrapper_objc_alias_method (VALUE rcv, VALUE new, VALUE old)
701{
702  id oc_rcv;
703  rbobj_to_nsobj(rcv, &oc_rcv);
704  _objc_alias_method((Class)oc_rcv, new, old);
705  return rcv;
706}
707
708static VALUE
709wrapper_objc_alias_class_method (VALUE rcv, VALUE new, VALUE old)
710{
711  id oc_rcv;
712  rbobj_to_nsobj(rcv, &oc_rcv);
713  _objc_alias_method((Class)(oc_rcv->isa), new, old);
714  return rcv;
715}
716
717/*****************************************/
718
719VALUE
720init_mdl_OCObjWrapper(VALUE outer)
721{
722  _mObjWrapper = rb_define_module_under(outer, "OCObjWrapper");
723
724  rb_define_method(_mObjWrapper, "ocm_responds?", wrapper_ocm_responds_p, 1);
725	//rb_define_method(_mObjWrapper, "ocm_conforms?", wrapper_ocm_conforms_p, 1);
726  rb_define_method(_mObjWrapper, "ocm_send", wrapper_ocm_send, -1);
727  rb_define_method(_mObjWrapper, "to_s", wrapper_to_s, 0);
728
729  rb_define_method(_mObjWrapper, "objc_methods", wrapper_objc_methods, 0);
730  rb_define_method(_mObjWrapper, "objc_method_type", wrapper_objc_method_type, 1);
731
732  _mClsWrapper = rb_define_module_under(outer, "OCClsWrapper");
733  rb_define_method(_mClsWrapper, "objc_instance_methods", wrapper_objc_instance_methods, -1);
734  rb_define_method(_mClsWrapper, "objc_class_methods", wrapper_objc_class_methods, -1);
735  rb_define_method(_mClsWrapper, "objc_instance_method_type", wrapper_objc_instance_method_type, 1);
736  rb_define_method(_mClsWrapper, "objc_class_method_type", wrapper_objc_class_method_type, 1);
737
738  rb_define_method(_mClsWrapper, "_objc_alias_method", wrapper_objc_alias_method, 2);
739  rb_define_method(_mClsWrapper, "_objc_alias_class_method", wrapper_objc_alias_class_method, 2);
740
741  rb_define_module_function(outer, "_ignore_ns_override", wrapper_ignore_ns_override, 0);
742  rb_define_module_function(outer, "_ignore_ns_override=", wrapper_ignore_ns_override_set, 1);
743
744  return Qnil;
745}
746