Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# ext/dl/cptr.c

Go to the documentation of this file.

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