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