|
Ruby
1.9.3p537(2014-02-19revision0)
|
00001 /* -*- C -*- 00002 * $Id$ 00003 */ 00004 00005 #include <ruby/ruby.h> 00006 #include <ruby/io.h> 00007 #include <ctype.h> 00008 #include "dl.h" 00009 00010 #ifdef PRIsVALUE 00011 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj) 00012 # define RB_OBJ_STRING(obj) (obj) 00013 #else 00014 # define PRIsVALUE "s" 00015 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj) 00016 # define RB_OBJ_STRING(obj) StringValueCStr(obj) 00017 #endif 00018 00019 VALUE rb_cDLCPtr; 00020 00021 static inline freefunc_t 00022 get_freefunc(VALUE func, volatile VALUE *wrap) 00023 { 00024 VALUE addrnum; 00025 if (NIL_P(func)) { 00026 *wrap = 0; 00027 return NULL; 00028 } 00029 if (rb_dlcfunc_kind_p(func)) { 00030 *wrap = func; 00031 return (freefunc_t)(VALUE)RCFUNC_DATA(func)->ptr; 00032 } 00033 addrnum = rb_Integer(func); 00034 *wrap = (addrnum != func) ? func : 0; 00035 return (freefunc_t)(VALUE)NUM2PTR(addrnum); 00036 } 00037 00038 static ID id_to_ptr; 00039 00040 static void 00041 dlptr_mark(void *ptr) 00042 { 00043 struct ptr_data *data = ptr; 00044 if (data->wrap[0]) { 00045 rb_gc_mark(data->wrap[0]); 00046 } 00047 if (data->wrap[1]) { 00048 rb_gc_mark(data->wrap[1]); 00049 } 00050 } 00051 00052 static void 00053 dlptr_free(void *ptr) 00054 { 00055 struct ptr_data *data = ptr; 00056 if (data->ptr) { 00057 if (data->free) { 00058 (*(data->free))(data->ptr); 00059 } 00060 } 00061 } 00062 00063 static size_t 00064 dlptr_memsize(const void *ptr) 00065 { 00066 const struct ptr_data *data = ptr; 00067 return data ? sizeof(*data) + data->size : 0; 00068 } 00069 00070 static const rb_data_type_t dlptr_data_type = { 00071 "dl/ptr", 00072 {dlptr_mark, dlptr_free, dlptr_memsize,}, 00073 }; 00074 00075 void 00076 dlptr_init(VALUE val) 00077 { 00078 struct ptr_data *data; 00079 00080 TypedData_Get_Struct(val, struct ptr_data, &dlptr_data_type, data); 00081 OBJ_TAINT(val); 00082 } 00083 00084 VALUE 00085 rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func) 00086 { 00087 struct ptr_data *data; 00088 VALUE val; 00089 00090 rb_secure(4); 00091 val = TypedData_Make_Struct(klass, struct ptr_data, &dlptr_data_type, data); 00092 data->ptr = ptr; 00093 data->free = func; 00094 data->size = size; 00095 dlptr_init(val); 00096 00097 return val; 00098 } 00099 00100 VALUE 00101 rb_dlptr_new(void *ptr, long size, freefunc_t func) 00102 { 00103 return rb_dlptr_new2(rb_cDLCPtr, ptr, size, func); 00104 } 00105 00106 VALUE 00107 rb_dlptr_malloc(long size, freefunc_t func) 00108 { 00109 void *ptr; 00110 00111 rb_secure(4); 00112 ptr = ruby_xmalloc((size_t)size); 00113 memset(ptr,0,(size_t)size); 00114 return rb_dlptr_new(ptr, size, func); 00115 } 00116 00117 void * 00118 rb_dlptr2cptr(VALUE val) 00119 { 00120 struct ptr_data *data; 00121 void *ptr; 00122 00123 if (rb_obj_is_kind_of(val, rb_cDLCPtr)) { 00124 TypedData_Get_Struct(val, struct ptr_data, &dlptr_data_type, data); 00125 ptr = data->ptr; 00126 } 00127 else if (val == Qnil) { 00128 ptr = NULL; 00129 } 00130 else{ 00131 rb_raise(rb_eTypeError, "DL::PtrData was expected"); 00132 } 00133 00134 return ptr; 00135 } 00136 00137 static VALUE 00138 rb_dlptr_s_allocate(VALUE klass) 00139 { 00140 VALUE obj; 00141 struct ptr_data *data; 00142 00143 rb_secure(4); 00144 obj = TypedData_Make_Struct(klass, struct ptr_data, &dlptr_data_type, data); 00145 data->ptr = 0; 00146 data->size = 0; 00147 data->free = 0; 00148 00149 return obj; 00150 } 00151 00152 /* 00153 * call-seq: 00154 * DL::CPtr.new(address) => dl_cptr 00155 * DL::CPtr.new(address, size) => dl_cptr 00156 * DL::CPtr.new(address, size, freefunc) => dl_cptr 00157 * 00158 * Create a new pointer to +address+ with an optional +size+ and +freefunc+. 00159 * +freefunc+ will be called when the instance is garbage collected. 00160 */ 00161 static VALUE 00162 rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) 00163 { 00164 VALUE ptr, sym, size, wrap = 0, funcwrap = 0; 00165 struct ptr_data *data; 00166 void *p = NULL; 00167 freefunc_t f = NULL; 00168 long s = 0; 00169 00170 if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) { 00171 VALUE addrnum = rb_Integer(ptr); 00172 if (addrnum != ptr) wrap = ptr; 00173 p = NUM2PTR(addrnum); 00174 } 00175 if (argc >= 2) { 00176 s = NUM2LONG(size); 00177 } 00178 if (argc >= 3) { 00179 f = get_freefunc(sym, &funcwrap); 00180 } 00181 00182 if (p) { 00183 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00184 if (data->ptr && data->free) { 00185 /* Free previous memory. Use of inappropriate initialize may cause SEGV. */ 00186 (*(data->free))(data->ptr); 00187 } 00188 data->wrap[0] = wrap; 00189 data->wrap[1] = funcwrap; 00190 data->ptr = p; 00191 data->size = s; 00192 data->free = f; 00193 } 00194 00195 return Qnil; 00196 } 00197 00198 /* 00199 * call-seq: 00200 * 00201 * DL::CPtr.malloc(size, freefunc = nil) => dl cptr instance 00202 * 00203 * Allocate +size+ bytes of memory and associate it with an optional 00204 * +freefunc+ that will be called when the pointer is garbage collected. 00205 * +freefunc+ must be an address pointing to a function or an instance of 00206 * DL::CFunc 00207 */ 00208 static VALUE 00209 rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) 00210 { 00211 VALUE size, sym, obj, wrap = 0; 00212 long s; 00213 freefunc_t f; 00214 00215 switch (rb_scan_args(argc, argv, "11", &size, &sym)) { 00216 case 1: 00217 s = NUM2LONG(size); 00218 f = NULL; 00219 break; 00220 case 2: 00221 s = NUM2LONG(size); 00222 f = get_freefunc(sym, &wrap); 00223 break; 00224 default: 00225 rb_bug("rb_dlptr_s_malloc"); 00226 } 00227 00228 obj = rb_dlptr_malloc(s,f); 00229 if (wrap) RPTR_DATA(obj)->wrap[1] = wrap; 00230 00231 return obj; 00232 } 00233 00234 /* 00235 * call-seq: to_i 00236 * 00237 * Returns the integer memory location of this DL::CPtr. 00238 */ 00239 static VALUE 00240 rb_dlptr_to_i(VALUE self) 00241 { 00242 struct ptr_data *data; 00243 00244 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00245 return PTR2NUM(data->ptr); 00246 } 00247 00248 /* 00249 * call-seq: to_value 00250 * 00251 * Cast this CPtr to a ruby object. 00252 */ 00253 static VALUE 00254 rb_dlptr_to_value(VALUE self) 00255 { 00256 struct ptr_data *data; 00257 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00258 return (VALUE)(data->ptr); 00259 } 00260 00261 /* 00262 * call-seq: ptr 00263 * 00264 * Returns a DL::CPtr that is a dereferenced pointer for this DL::CPtr. 00265 * Analogous to the star operator in C. 00266 */ 00267 VALUE 00268 rb_dlptr_ptr(VALUE self) 00269 { 00270 struct ptr_data *data; 00271 00272 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00273 return rb_dlptr_new(*((void**)(data->ptr)),0,0); 00274 } 00275 00276 /* 00277 * call-seq: ref 00278 * 00279 * Returns a DL::CPtr that is a reference pointer for this DL::CPtr. 00280 * Analogous to the ampersand operator in C. 00281 */ 00282 VALUE 00283 rb_dlptr_ref(VALUE self) 00284 { 00285 struct ptr_data *data; 00286 00287 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00288 return rb_dlptr_new(&(data->ptr),0,0); 00289 } 00290 00291 /* 00292 * call-seq: null? 00293 * 00294 * Returns true if this is a null pointer. 00295 */ 00296 VALUE 00297 rb_dlptr_null_p(VALUE self) 00298 { 00299 struct ptr_data *data; 00300 00301 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00302 return data->ptr ? Qfalse : Qtrue; 00303 } 00304 00305 /* 00306 * call-seq: free=(function) 00307 * 00308 * Set the free function for this pointer to the DL::CFunc in +function+. 00309 */ 00310 static VALUE 00311 rb_dlptr_free_set(VALUE self, VALUE val) 00312 { 00313 struct ptr_data *data; 00314 00315 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00316 data->free = get_freefunc(val, &data->wrap[1]); 00317 00318 return Qnil; 00319 } 00320 00321 /* 00322 * call-seq: free 00323 * 00324 * Get the free function for this pointer. Returns DL::CFunc or nil. 00325 */ 00326 static VALUE 00327 rb_dlptr_free_get(VALUE self) 00328 { 00329 struct ptr_data *pdata; 00330 00331 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, pdata); 00332 00333 return rb_dlcfunc_new(pdata->free, DLTYPE_VOID, "free<anonymous>", CFUNC_CDECL); 00334 } 00335 00336 /* 00337 * call-seq: 00338 * 00339 * ptr.to_s => string 00340 * ptr.to_s(len) => string 00341 * 00342 * Returns the pointer contents as a string. When called with no arguments, 00343 * this method will return the contents until the first NULL byte. When 00344 * called with +len+, a string of +len+ bytes will be returned. 00345 */ 00346 static VALUE 00347 rb_dlptr_to_s(int argc, VALUE argv[], VALUE self) 00348 { 00349 struct ptr_data *data; 00350 VALUE arg1, val; 00351 int len; 00352 00353 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00354 switch (rb_scan_args(argc, argv, "01", &arg1)) { 00355 case 0: 00356 val = rb_tainted_str_new2((char*)(data->ptr)); 00357 break; 00358 case 1: 00359 len = NUM2INT(arg1); 00360 val = rb_tainted_str_new((char*)(data->ptr), len); 00361 break; 00362 default: 00363 rb_bug("rb_dlptr_to_s"); 00364 } 00365 00366 return val; 00367 } 00368 00369 /* 00370 * call-seq: 00371 * 00372 * ptr.to_str => string 00373 * ptr.to_str(len) => string 00374 * 00375 * Returns the pointer contents as a string. When called with no arguments, 00376 * this method will return the contents with the length of this pointer's 00377 * +size+. When called with +len+, a string of +len+ bytes will be returned. 00378 */ 00379 static VALUE 00380 rb_dlptr_to_str(int argc, VALUE argv[], VALUE self) 00381 { 00382 struct ptr_data *data; 00383 VALUE arg1, val; 00384 int len; 00385 00386 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00387 switch (rb_scan_args(argc, argv, "01", &arg1)) { 00388 case 0: 00389 val = rb_tainted_str_new((char*)(data->ptr),data->size); 00390 break; 00391 case 1: 00392 len = NUM2INT(arg1); 00393 val = rb_tainted_str_new((char*)(data->ptr), len); 00394 break; 00395 default: 00396 rb_bug("rb_dlptr_to_str"); 00397 } 00398 00399 return val; 00400 } 00401 00402 /* 00403 * call-seq: inspect 00404 * 00405 * Returns a string formatted with an easily readable representation of the 00406 * internal state of the DL::CPtr 00407 */ 00408 static VALUE 00409 rb_dlptr_inspect(VALUE self) 00410 { 00411 struct ptr_data *data; 00412 00413 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00414 return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>", 00415 RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free); 00416 } 00417 00418 /* 00419 * call-seq: 00420 * ptr == other => true or false 00421 * ptr.eql?(other) => true or false 00422 * 00423 * Returns true if +other+ wraps the same pointer, otherwise returns 00424 * false. 00425 */ 00426 VALUE 00427 rb_dlptr_eql(VALUE self, VALUE other) 00428 { 00429 void *ptr1, *ptr2; 00430 00431 if(!rb_obj_is_kind_of(other, rb_cDLCPtr)) return Qfalse; 00432 00433 ptr1 = rb_dlptr2cptr(self); 00434 ptr2 = rb_dlptr2cptr(other); 00435 00436 return ptr1 == ptr2 ? Qtrue : Qfalse; 00437 } 00438 00439 /* 00440 * call-seq: 00441 * ptr <=> other => -1, 0, 1, or nil 00442 * 00443 * Returns -1 if less than, 0 if equal to, 1 if greater than +other+. Returns 00444 * nil if +ptr+ cannot be compared to +other+. 00445 */ 00446 static VALUE 00447 rb_dlptr_cmp(VALUE self, VALUE other) 00448 { 00449 void *ptr1, *ptr2; 00450 SIGNED_VALUE diff; 00451 00452 if(!rb_obj_is_kind_of(other, rb_cDLCPtr)) return Qnil; 00453 00454 ptr1 = rb_dlptr2cptr(self); 00455 ptr2 = rb_dlptr2cptr(other); 00456 diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2; 00457 if (!diff) return INT2FIX(0); 00458 return diff > 0 ? INT2NUM(1) : INT2NUM(-1); 00459 } 00460 00461 /* 00462 * call-seq: 00463 * ptr + n => new cptr 00464 * 00465 * Returns a new DL::CPtr that has been advanced +n+ bytes. 00466 */ 00467 static VALUE 00468 rb_dlptr_plus(VALUE self, VALUE other) 00469 { 00470 void *ptr; 00471 long num, size; 00472 00473 ptr = rb_dlptr2cptr(self); 00474 size = RPTR_DATA(self)->size; 00475 num = NUM2LONG(other); 00476 return rb_dlptr_new((char *)ptr + num, size - num, 0); 00477 } 00478 00479 /* 00480 * call-seq: 00481 * ptr - n => new cptr 00482 * 00483 * Returns a new DL::CPtr that has been moved back +n+ bytes. 00484 */ 00485 static VALUE 00486 rb_dlptr_minus(VALUE self, VALUE other) 00487 { 00488 void *ptr; 00489 long num, size; 00490 00491 ptr = rb_dlptr2cptr(self); 00492 size = RPTR_DATA(self)->size; 00493 num = NUM2LONG(other); 00494 return rb_dlptr_new((char *)ptr - num, size + num, 0); 00495 } 00496 00497 /* 00498 * call-seq: 00499 * ptr[index] -> an_integer 00500 * ptr[start, length] -> a_string 00501 * 00502 * Returns integer stored at _index_. If _start_ and _length_ are given, 00503 * a string containing the bytes from _start_ of length _length_ will be 00504 * returned. 00505 */ 00506 VALUE 00507 rb_dlptr_aref(int argc, VALUE argv[], VALUE self) 00508 { 00509 VALUE arg0, arg1; 00510 VALUE retval = Qnil; 00511 size_t offset, len; 00512 struct ptr_data *data; 00513 00514 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00515 if (!data->ptr) rb_raise(rb_eDLError, "NULL pointer dereference"); 00516 switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){ 00517 case 1: 00518 offset = NUM2ULONG(arg0); 00519 retval = INT2NUM(*((char *)data->ptr + offset)); 00520 break; 00521 case 2: 00522 offset = NUM2ULONG(arg0); 00523 len = NUM2ULONG(arg1); 00524 retval = rb_tainted_str_new((char *)data->ptr + offset, len); 00525 break; 00526 default: 00527 rb_bug("rb_dlptr_aref()"); 00528 } 00529 return retval; 00530 } 00531 00532 /* 00533 * call-seq: 00534 * ptr[index] = int -> int 00535 * ptr[start, length] = string or cptr or addr -> string or dl_cptr or addr 00536 * 00537 * Set the value at +index+ to +int+. Or, set the memory at +start+ until 00538 * +length+ with the contents of +string+, the memory from +dl_cptr+, or the 00539 * memory pointed at by the memory address +addr+. 00540 */ 00541 VALUE 00542 rb_dlptr_aset(int argc, VALUE argv[], VALUE self) 00543 { 00544 VALUE arg0, arg1, arg2; 00545 VALUE retval = Qnil; 00546 size_t offset, len; 00547 void *mem; 00548 struct ptr_data *data; 00549 00550 TypedData_Get_Struct(self, struct ptr_data, &dlptr_data_type, data); 00551 if (!data->ptr) rb_raise(rb_eDLError, "NULL pointer dereference"); 00552 switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){ 00553 case 2: 00554 offset = NUM2ULONG(arg0); 00555 ((char*)data->ptr)[offset] = NUM2UINT(arg1); 00556 retval = arg1; 00557 break; 00558 case 3: 00559 offset = NUM2ULONG(arg0); 00560 len = NUM2ULONG(arg1); 00561 if (RB_TYPE_P(arg2, T_STRING)) { 00562 mem = StringValuePtr(arg2); 00563 } 00564 else if( rb_obj_is_kind_of(arg2, rb_cDLCPtr) ){ 00565 mem = rb_dlptr2cptr(arg2); 00566 } 00567 else{ 00568 mem = NUM2PTR(arg2); 00569 } 00570 memcpy((char *)data->ptr + offset, mem, len); 00571 retval = arg2; 00572 break; 00573 default: 00574 rb_bug("rb_dlptr_aset()"); 00575 } 00576 return retval; 00577 } 00578 00579 /* 00580 * call-seq: size=(size) 00581 * 00582 * Set the size of this pointer to +size+ 00583 */ 00584 static VALUE 00585 rb_dlptr_size_set(VALUE self, VALUE size) 00586 { 00587 RPTR_DATA(self)->size = NUM2LONG(size); 00588 return size; 00589 } 00590 00591 /* 00592 * call-seq: size 00593 * 00594 * Get the size of this pointer. 00595 */ 00596 static VALUE 00597 rb_dlptr_size_get(VALUE self) 00598 { 00599 return LONG2NUM(RPTR_DATA(self)->size); 00600 } 00601 00602 /* 00603 * call-seq: 00604 * DL::CPtr.to_ptr(val) => cptr 00605 * DL::CPtr[val] => cptr 00606 * 00607 * Get the underlying pointer for ruby object +val+ and return it as a 00608 * DL::CPtr object. 00609 */ 00610 static VALUE 00611 rb_dlptr_s_to_ptr(VALUE self, VALUE val) 00612 { 00613 VALUE ptr, wrap = val, vptr; 00614 00615 if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){ 00616 rb_io_t *fptr; 00617 FILE *fp; 00618 GetOpenFile(val, fptr); 00619 fp = rb_io_stdio_file(fptr); 00620 ptr = rb_dlptr_new(fp, 0, NULL); 00621 } 00622 else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){ 00623 char *str = StringValuePtr(val); 00624 ptr = rb_dlptr_new(str, RSTRING_LEN(val), NULL); 00625 } 00626 else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){ 00627 if (rb_obj_is_kind_of(vptr, rb_cDLCPtr)){ 00628 ptr = vptr; 00629 wrap = 0; 00630 } 00631 else{ 00632 rb_raise(rb_eDLError, "to_ptr should return a CPtr object"); 00633 } 00634 } 00635 else{ 00636 VALUE num = rb_Integer(val); 00637 if (num == val) wrap = 0; 00638 ptr = rb_dlptr_new(NUM2PTR(num), 0, NULL); 00639 } 00640 OBJ_INFECT(ptr, val); 00641 if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap; 00642 return ptr; 00643 } 00644 00645 void 00646 Init_dlptr(void) 00647 { 00648 id_to_ptr = rb_intern("to_ptr"); 00649 00650 /* Document-class: DL::CPtr 00651 * 00652 * CPtr is a class to handle C pointers 00653 * 00654 */ 00655 rb_cDLCPtr = rb_define_class_under(rb_mDL, "CPtr", rb_cObject); 00656 rb_define_alloc_func(rb_cDLCPtr, rb_dlptr_s_allocate); 00657 rb_define_singleton_method(rb_cDLCPtr, "malloc", rb_dlptr_s_malloc, -1); 00658 rb_define_singleton_method(rb_cDLCPtr, "to_ptr", rb_dlptr_s_to_ptr, 1); 00659 rb_define_singleton_method(rb_cDLCPtr, "[]", rb_dlptr_s_to_ptr, 1); 00660 rb_define_method(rb_cDLCPtr, "initialize", rb_dlptr_initialize, -1); 00661 rb_define_method(rb_cDLCPtr, "free=", rb_dlptr_free_set, 1); 00662 rb_define_method(rb_cDLCPtr, "free", rb_dlptr_free_get, 0); 00663 rb_define_method(rb_cDLCPtr, "to_i", rb_dlptr_to_i, 0); 00664 rb_define_method(rb_cDLCPtr, "to_int", rb_dlptr_to_i, 0); 00665 rb_define_method(rb_cDLCPtr, "to_value", rb_dlptr_to_value, 0); 00666 rb_define_method(rb_cDLCPtr, "ptr", rb_dlptr_ptr, 0); 00667 rb_define_method(rb_cDLCPtr, "+@", rb_dlptr_ptr, 0); 00668 rb_define_method(rb_cDLCPtr, "ref", rb_dlptr_ref, 0); 00669 rb_define_method(rb_cDLCPtr, "-@", rb_dlptr_ref, 0); 00670 rb_define_method(rb_cDLCPtr, "null?", rb_dlptr_null_p, 0); 00671 rb_define_method(rb_cDLCPtr, "to_s", rb_dlptr_to_s, -1); 00672 rb_define_method(rb_cDLCPtr, "to_str", rb_dlptr_to_str, -1); 00673 rb_define_method(rb_cDLCPtr, "inspect", rb_dlptr_inspect, 0); 00674 rb_define_method(rb_cDLCPtr, "<=>", rb_dlptr_cmp, 1); 00675 rb_define_method(rb_cDLCPtr, "==", rb_dlptr_eql, 1); 00676 rb_define_method(rb_cDLCPtr, "eql?", rb_dlptr_eql, 1); 00677 rb_define_method(rb_cDLCPtr, "+", rb_dlptr_plus, 1); 00678 rb_define_method(rb_cDLCPtr, "-", rb_dlptr_minus, 1); 00679 rb_define_method(rb_cDLCPtr, "[]", rb_dlptr_aref, -1); 00680 rb_define_method(rb_cDLCPtr, "[]=", rb_dlptr_aset, -1); 00681 rb_define_method(rb_cDLCPtr, "size", rb_dlptr_size_get, 0); 00682 rb_define_method(rb_cDLCPtr, "size=", rb_dlptr_size_set, 1); 00683 00684 /* Document-const: NULL 00685 * 00686 * A NULL pointer 00687 */ 00688 rb_define_const(rb_mDL, "NULL", rb_dlptr_new(0, 0, 0)); 00689 } 00690
1.7.6.1