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 "cls_objcid.h" 11 12#import "osx_ruby.h" 13#import "ocdata_conv.h" 14#import <Foundation/Foundation.h> 15#import <string.h> 16#import <stdlib.h> 17#import "RBObject.h" 18#import "internal_macros.h" 19#import "BridgeSupport.h" 20#import "mdl_osxobjc.h" 21 22static VALUE _kObjcID = Qnil; 23 24static void 25_objcid_data_free(struct _objcid_data* dp) 26{ 27 id pool = [[NSAutoreleasePool alloc] init]; 28 if (dp != NULL) { 29 if (dp->ocid != nil) { 30 remove_from_oc2rb_cache(dp->ocid); 31 if (dp->retained && dp->can_be_released) { 32 DLOG("CLSOBJ", "releasing %p", dp->ocid); 33 [dp->ocid release]; 34 } 35 } 36 free(dp); 37 } 38 [pool release]; 39} 40 41static struct _objcid_data* 42_objcid_data_new() 43{ 44 struct _objcid_data* dp; 45 dp = malloc(sizeof(struct _objcid_data)); 46 dp->ocid = nil; 47 dp->retained = NO; 48 dp->can_be_released = NO; 49 return dp; 50} 51 52static VALUE 53objcid_s_new(int argc, VALUE* argv, VALUE klass) 54{ 55 VALUE obj; 56 obj = Data_Wrap_Struct(klass, NULL, _objcid_data_free, _objcid_data_new()); 57 rb_obj_call_init(obj, argc, argv); 58 return obj; 59} 60 61VALUE 62objcid_new_with_ocid(VALUE klass, id ocid) 63{ 64 VALUE obj; 65 66 obj = Data_Wrap_Struct(klass, 0, _objcid_data_free, _objcid_data_new()); 67 68 // The retention of the ObjC instance is delayed in ocm_send, to not 69 // violate the "init-must-follow-alloc" initialization pattern. 70 // Retaining here could message in the middle. 71 if (ocid != nil) { 72 OBJCID_DATA_PTR(obj)->ocid = ocid; 73 OBJCID_DATA_PTR(obj)->retained = NO; 74 } 75 76 rb_obj_call_init(obj, 0, NULL); 77 return obj; 78} 79 80static VALUE 81wrapper_objcid_s_new_with_ocid(VALUE klass, VALUE rbocid) 82{ 83 return objcid_new_with_ocid(klass, NUM2OCID(rbocid)); 84} 85 86static VALUE 87objcid_release(VALUE rcv) 88{ 89 if (OBJCID_DATA_PTR(rcv)->can_be_released) { 90 [OBJCID_ID(rcv) release]; 91 OBJCID_DATA_PTR(rcv)->can_be_released = NO; 92 } 93 return rcv; 94} 95 96static VALUE 97objcid_initialize(int argc, VALUE* argv, VALUE rcv) 98{ 99 return rcv; 100} 101 102static VALUE 103objcid_ocid(VALUE rcv) 104{ 105 return OCID2NUM(OBJCID_ID(rcv)); 106} 107 108static VALUE 109objcid_inspect(VALUE rcv) 110{ 111 char s[512]; 112 id ocid; 113 struct bsConst * bs_const; 114 const char * class_desc; 115 id pool; 116 117 ocid = OBJCID_ID(rcv); 118 bs_const = find_magic_cookie_const_by_value(ocid); 119 if (bs_const != NULL) { 120 pool = nil; 121 class_desc = bs_const->class_name; 122 } 123 else { 124 pool = [[NSAutoreleasePool alloc] init]; 125 class_desc = [[[ocid class] description] UTF8String]; 126 } 127 128 snprintf(s, sizeof(s), "#<%s:0x%lx class='%s' id=%p>", 129 rb_class2name(CLASS_OF(rcv)), 130 NUM2ULONG(rb_obj_id(rcv)), 131 class_desc, ocid); 132 133 if (pool != nil) 134 [pool release]; 135 136 return rb_str_new2(s); 137} 138 139/** class methods **/ 140 141VALUE 142objid_s_class () 143{ 144 return _kObjcID; 145} 146 147/*******/ 148 149VALUE 150init_cls_ObjcID(VALUE outer) 151{ 152 _kObjcID = rb_define_class_under(outer, "ObjcID", rb_cObject); 153 154 rb_define_singleton_method(_kObjcID, "new", objcid_s_new, -1); 155 rb_define_singleton_method(_kObjcID, "new_with_ocid", wrapper_objcid_s_new_with_ocid, 1); 156 157 rb_define_method(_kObjcID, "initialize", objcid_initialize, -1); 158 rb_define_method(_kObjcID, "__ocid__", objcid_ocid, 0); 159 rb_define_method(_kObjcID, "__inspect__", objcid_inspect, 0); 160 rb_define_method(_kObjcID, "release", objcid_release, 0); 161 rb_define_method(_kObjcID, "inspect", objcid_inspect, 0); 162 163 return _kObjcID; 164} 165