Ruby  1.9.3p537(2014-02-19revision0)
ext/dl/cptr.c
Go to the documentation of this file.
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