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