Ruby  2.0.0p594(2014-10-27revision48167)
ext/fiddle/pointer.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 <fiddle.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_cPointer;
00020 
00021 typedef void (*freefunc_t)(void*);
00022 
00023 struct ptr_data {
00024     void *ptr;
00025     long size;
00026     freefunc_t free;
00027     VALUE wrap[2];
00028 };
00029 
00030 #define RPTR_DATA(obj) ((struct ptr_data *)(DATA_PTR(obj)))
00031 
00032 static inline freefunc_t
00033 get_freefunc(VALUE func, volatile VALUE *wrap)
00034 {
00035     VALUE addrnum;
00036     if (NIL_P(func)) {
00037         *wrap = 0;
00038         return NULL;
00039     }
00040     addrnum = rb_Integer(func);
00041     *wrap = (addrnum != func) ? func : 0;
00042     return (freefunc_t)(VALUE)NUM2PTR(addrnum);
00043 }
00044 
00045 static ID id_to_ptr;
00046 
00047 static void
00048 fiddle_ptr_mark(void *ptr)
00049 {
00050     struct ptr_data *data = ptr;
00051     if (data->wrap[0]) {
00052         rb_gc_mark(data->wrap[0]);
00053     }
00054     if (data->wrap[1]) {
00055         rb_gc_mark(data->wrap[1]);
00056     }
00057 }
00058 
00059 static void
00060 fiddle_ptr_free(void *ptr)
00061 {
00062     struct ptr_data *data = ptr;
00063     if (data->ptr) {
00064         if (data->free) {
00065             (*(data->free))(data->ptr);
00066         }
00067     }
00068     xfree(ptr);
00069 }
00070 
00071 static size_t
00072 fiddle_ptr_memsize(const void *ptr)
00073 {
00074     const struct ptr_data *data = ptr;
00075     return data ? sizeof(*data) + data->size : 0;
00076 }
00077 
00078 static const rb_data_type_t fiddle_ptr_data_type = {
00079     "fiddle/pointer",
00080     {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
00081 };
00082 
00083 static VALUE
00084 rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
00085 {
00086     struct ptr_data *data;
00087     VALUE val;
00088 
00089     rb_secure(4);
00090     val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
00091     data->ptr = ptr;
00092     data->free = func;
00093     data->size = size;
00094     OBJ_TAINT(val);
00095 
00096     return val;
00097 }
00098 
00099 static VALUE
00100 rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
00101 {
00102     return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func);
00103 }
00104 
00105 static VALUE
00106 rb_fiddle_ptr_malloc(long size, freefunc_t func)
00107 {
00108     void *ptr;
00109 
00110     rb_secure(4);
00111     ptr = ruby_xmalloc((size_t)size);
00112     memset(ptr,0,(size_t)size);
00113     return rb_fiddle_ptr_new(ptr, size, func);
00114 }
00115 
00116 static void *
00117 rb_fiddle_ptr2cptr(VALUE val)
00118 {
00119     struct ptr_data *data;
00120     void *ptr;
00121 
00122     if (rb_obj_is_kind_of(val, rb_cPointer)) {
00123         TypedData_Get_Struct(val, struct ptr_data, &fiddle_ptr_data_type, data);
00124         ptr = data->ptr;
00125     }
00126     else if (val == Qnil) {
00127         ptr = NULL;
00128     }
00129     else{
00130         rb_raise(rb_eTypeError, "Fiddle::Pointer was expected");
00131     }
00132 
00133     return ptr;
00134 }
00135 
00136 static VALUE
00137 rb_fiddle_ptr_s_allocate(VALUE klass)
00138 {
00139     VALUE obj;
00140     struct ptr_data *data;
00141 
00142     rb_secure(4);
00143     obj = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
00144     data->ptr = 0;
00145     data->size = 0;
00146     data->free = 0;
00147 
00148     return obj;
00149 }
00150 
00151 /*
00152  * call-seq:
00153  *    Fiddle::Pointer.new(address)      => fiddle_cptr
00154  *    new(address, size)                => fiddle_cptr
00155  *    new(address, size, freefunc)      => fiddle_cptr
00156  *
00157  * Create a new pointer to +address+ with an optional +size+ and +freefunc+.
00158  *
00159  * +freefunc+ will be called when the instance is garbage collected.
00160  */
00161 static VALUE
00162 rb_fiddle_ptr_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, &fiddle_ptr_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  *    Fiddle::Pointer.malloc(size, freefunc = nil)  => fiddle pointer 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  *
00206  * +freefunc+ must be an address pointing to a function or an instance of
00207  * Fiddle::Function
00208  */
00209 static VALUE
00210 rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
00211 {
00212     VALUE size, sym, obj, wrap = 0;
00213     long s;
00214     freefunc_t f;
00215 
00216     switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
00217       case 1:
00218         s = NUM2LONG(size);
00219         f = NULL;
00220         break;
00221       case 2:
00222         s = NUM2LONG(size);
00223         f = get_freefunc(sym, &wrap);
00224         break;
00225       default:
00226         rb_bug("rb_fiddle_ptr_s_malloc");
00227     }
00228 
00229     obj = rb_fiddle_ptr_malloc(s,f);
00230     if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
00231 
00232     return obj;
00233 }
00234 
00235 /*
00236  * call-seq: to_i
00237  *
00238  * Returns the integer memory location of this pointer.
00239  */
00240 static VALUE
00241 rb_fiddle_ptr_to_i(VALUE self)
00242 {
00243     struct ptr_data *data;
00244 
00245     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00246     return PTR2NUM(data->ptr);
00247 }
00248 
00249 /*
00250  * call-seq: to_value
00251  *
00252  * Cast this pointer to a ruby object.
00253  */
00254 static VALUE
00255 rb_fiddle_ptr_to_value(VALUE self)
00256 {
00257     struct ptr_data *data;
00258     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00259     return (VALUE)(data->ptr);
00260 }
00261 
00262 /*
00263  * call-seq: ptr
00264  *
00265  * Returns a new Fiddle::Pointer instance that is a dereferenced pointer for
00266  * this pointer.
00267  *
00268  * Analogous to the star operator in C.
00269  */
00270 static VALUE
00271 rb_fiddle_ptr_ptr(VALUE self)
00272 {
00273     struct ptr_data *data;
00274 
00275     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00276     return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
00277 }
00278 
00279 /*
00280  * call-seq: ref
00281  *
00282  * Returns a new Fiddle::Pointer instance that is a reference pointer for this
00283  * pointer.
00284  *
00285  * Analogous to the ampersand operator in C.
00286  */
00287 static VALUE
00288 rb_fiddle_ptr_ref(VALUE self)
00289 {
00290     struct ptr_data *data;
00291 
00292     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00293     return rb_fiddle_ptr_new(&(data->ptr),0,0);
00294 }
00295 
00296 /*
00297  * call-seq: null?
00298  *
00299  * Returns +true+ if this is a null pointer.
00300  */
00301 static VALUE
00302 rb_fiddle_ptr_null_p(VALUE self)
00303 {
00304     struct ptr_data *data;
00305 
00306     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00307     return data->ptr ? Qfalse : Qtrue;
00308 }
00309 
00310 /*
00311  * call-seq: free=(function)
00312  *
00313  * Set the free function for this pointer to +function+ in the given
00314  * Fiddle::Function.
00315  */
00316 static VALUE
00317 rb_fiddle_ptr_free_set(VALUE self, VALUE val)
00318 {
00319     struct ptr_data *data;
00320 
00321     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00322     data->free = get_freefunc(val, &data->wrap[1]);
00323 
00324     return Qnil;
00325 }
00326 
00327 /*
00328  * call-seq: free => Fiddle::Function
00329  *
00330  * Get the free function for this pointer.
00331  *
00332  * Returns a new instance of Fiddle::Function.
00333  *
00334  * See Fiddle::Function.new
00335  */
00336 static VALUE
00337 rb_fiddle_ptr_free_get(VALUE self)
00338 {
00339     struct ptr_data *pdata;
00340     VALUE address;
00341     VALUE arg_types;
00342     VALUE ret_type;
00343 
00344     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
00345 
00346     if (!pdata->free)
00347         return Qnil;
00348 
00349     address = PTR2NUM(pdata->free);
00350     ret_type = INT2NUM(TYPE_VOID);
00351     arg_types = rb_ary_new();
00352     rb_ary_push(arg_types, INT2NUM(TYPE_VOIDP));
00353 
00354     return rb_fiddle_new_function(address, arg_types, ret_type);
00355 }
00356 
00357 /*
00358  * call-seq:
00359  *
00360  *    ptr.to_s        => string
00361  *    ptr.to_s(len)   => string
00362  *
00363  * Returns the pointer contents as a string.
00364  *
00365  * When called with no arguments, this method will return the contents until
00366  * the first NULL byte.
00367  *
00368  * When called with +len+, a string of +len+ bytes will be returned.
00369  *
00370  * See to_str
00371  */
00372 static VALUE
00373 rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
00374 {
00375     struct ptr_data *data;
00376     VALUE arg1, val;
00377     int len;
00378 
00379     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00380     switch (rb_scan_args(argc, argv, "01", &arg1)) {
00381       case 0:
00382         val = rb_tainted_str_new2((char*)(data->ptr));
00383         break;
00384       case 1:
00385         len = NUM2INT(arg1);
00386         val = rb_tainted_str_new((char*)(data->ptr), len);
00387         break;
00388       default:
00389         rb_bug("rb_fiddle_ptr_to_s");
00390     }
00391 
00392     return val;
00393 }
00394 
00395 /*
00396  * call-seq:
00397  *
00398  *    ptr.to_str        => string
00399  *    ptr.to_str(len)   => string
00400  *
00401  * Returns the pointer contents as a string.
00402  *
00403  * When called with no arguments, this method will return the contents with the
00404  * length of this pointer's +size+.
00405  *
00406  * When called with +len+, a string of +len+ bytes will be returned.
00407  *
00408  * See to_s
00409  */
00410 static VALUE
00411 rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
00412 {
00413     struct ptr_data *data;
00414     VALUE arg1, val;
00415     int len;
00416 
00417     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00418     switch (rb_scan_args(argc, argv, "01", &arg1)) {
00419       case 0:
00420         val = rb_tainted_str_new((char*)(data->ptr),data->size);
00421         break;
00422       case 1:
00423         len = NUM2INT(arg1);
00424         val = rb_tainted_str_new((char*)(data->ptr), len);
00425         break;
00426       default:
00427         rb_bug("rb_fiddle_ptr_to_str");
00428     }
00429 
00430     return val;
00431 }
00432 
00433 /*
00434  * call-seq: inspect
00435  *
00436  * Returns a string formatted with an easily readable representation of the
00437  * internal state of the pointer.
00438  */
00439 static VALUE
00440 rb_fiddle_ptr_inspect(VALUE self)
00441 {
00442     struct ptr_data *data;
00443 
00444     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00445     return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
00446                       RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
00447 }
00448 
00449 /*
00450  *  call-seq:
00451  *    ptr == other    => true or false
00452  *    ptr.eql?(other) => true or false
00453  *
00454  * Returns true if +other+ wraps the same pointer, otherwise returns
00455  * false.
00456  */
00457 static VALUE
00458 rb_fiddle_ptr_eql(VALUE self, VALUE other)
00459 {
00460     void *ptr1, *ptr2;
00461 
00462     if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;
00463 
00464     ptr1 = rb_fiddle_ptr2cptr(self);
00465     ptr2 = rb_fiddle_ptr2cptr(other);
00466 
00467     return ptr1 == ptr2 ? Qtrue : Qfalse;
00468 }
00469 
00470 /*
00471  *  call-seq:
00472  *    ptr <=> other   => -1, 0, 1, or nil
00473  *
00474  * Returns -1 if less than, 0 if equal to, 1 if greater than +other+.
00475  *
00476  * Returns nil if +ptr+ cannot be compared to +other+.
00477  */
00478 static VALUE
00479 rb_fiddle_ptr_cmp(VALUE self, VALUE other)
00480 {
00481     void *ptr1, *ptr2;
00482     SIGNED_VALUE diff;
00483 
00484     if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qnil;
00485 
00486     ptr1 = rb_fiddle_ptr2cptr(self);
00487     ptr2 = rb_fiddle_ptr2cptr(other);
00488     diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
00489     if (!diff) return INT2FIX(0);
00490     return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
00491 }
00492 
00493 /*
00494  * call-seq:
00495  *    ptr + n   => new cptr
00496  *
00497  * Returns a new pointer instance that has been advanced +n+ bytes.
00498  */
00499 static VALUE
00500 rb_fiddle_ptr_plus(VALUE self, VALUE other)
00501 {
00502     void *ptr;
00503     long num, size;
00504 
00505     ptr = rb_fiddle_ptr2cptr(self);
00506     size = RPTR_DATA(self)->size;
00507     num = NUM2LONG(other);
00508     return rb_fiddle_ptr_new((char *)ptr + num, size - num, 0);
00509 }
00510 
00511 /*
00512  * call-seq:
00513  *    ptr - n   => new cptr
00514  *
00515  * Returns a new pointer instance that has been moved back +n+ bytes.
00516  */
00517 static VALUE
00518 rb_fiddle_ptr_minus(VALUE self, VALUE other)
00519 {
00520     void *ptr;
00521     long num, size;
00522 
00523     ptr = rb_fiddle_ptr2cptr(self);
00524     size = RPTR_DATA(self)->size;
00525     num = NUM2LONG(other);
00526     return rb_fiddle_ptr_new((char *)ptr - num, size + num, 0);
00527 }
00528 
00529 /*
00530  *  call-seq:
00531  *     ptr[index]                -> an_integer
00532  *     ptr[start, length]        -> a_string
00533  *
00534  * Returns integer stored at _index_.
00535  *
00536  * If _start_ and _length_ are given, a string containing the bytes from
00537  * _start_ of _length_ will be returned.
00538  */
00539 static VALUE
00540 rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
00541 {
00542     VALUE arg0, arg1;
00543     VALUE retval = Qnil;
00544     size_t offset, len;
00545     struct ptr_data *data;
00546 
00547     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00548     if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
00549     switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
00550       case 1:
00551         offset = NUM2ULONG(arg0);
00552         retval = INT2NUM(*((char *)data->ptr + offset));
00553         break;
00554       case 2:
00555         offset = NUM2ULONG(arg0);
00556         len    = NUM2ULONG(arg1);
00557         retval = rb_tainted_str_new((char *)data->ptr + offset, len);
00558         break;
00559       default:
00560         rb_bug("rb_fiddle_ptr_aref()");
00561     }
00562     return retval;
00563 }
00564 
00565 /*
00566  *  call-seq:
00567  *     ptr[index]         = int                    ->  int
00568  *     ptr[start, length] = string or cptr or addr ->  string or dl_cptr or addr
00569  *
00570  * Set the value at +index+ to +int+.
00571  *
00572  * Or, set the memory at +start+ until +length+ with the contents of +string+,
00573  * the memory from +dl_cptr+, or the memory pointed at by the memory address
00574  * +addr+.
00575  */
00576 static VALUE
00577 rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
00578 {
00579     VALUE arg0, arg1, arg2;
00580     VALUE retval = Qnil;
00581     size_t offset, len;
00582     void *mem;
00583     struct ptr_data *data;
00584 
00585     TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
00586     if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
00587     switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
00588       case 2:
00589         offset = NUM2ULONG(arg0);
00590         ((char*)data->ptr)[offset] = NUM2UINT(arg1);
00591         retval = arg1;
00592         break;
00593       case 3:
00594         offset = NUM2ULONG(arg0);
00595         len    = NUM2ULONG(arg1);
00596         if (RB_TYPE_P(arg2, T_STRING)) {
00597             mem = StringValuePtr(arg2);
00598         }
00599         else if( rb_obj_is_kind_of(arg2, rb_cPointer) ){
00600             mem = rb_fiddle_ptr2cptr(arg2);
00601         }
00602         else{
00603             mem    = NUM2PTR(arg2);
00604         }
00605         memcpy((char *)data->ptr + offset, mem, len);
00606         retval = arg2;
00607         break;
00608       default:
00609         rb_bug("rb_fiddle_ptr_aset()");
00610     }
00611     return retval;
00612 }
00613 
00614 /*
00615  * call-seq: size=(size)
00616  *
00617  * Set the size of this pointer to +size+
00618  */
00619 static VALUE
00620 rb_fiddle_ptr_size_set(VALUE self, VALUE size)
00621 {
00622     RPTR_DATA(self)->size = NUM2LONG(size);
00623     return size;
00624 }
00625 
00626 /*
00627  * call-seq: size
00628  *
00629  * Get the size of this pointer.
00630  */
00631 static VALUE
00632 rb_fiddle_ptr_size_get(VALUE self)
00633 {
00634     return LONG2NUM(RPTR_DATA(self)->size);
00635 }
00636 
00637 /*
00638  * call-seq:
00639  *    Fiddle::Pointer[val]         => cptr
00640  *    to_ptr(val)  => cptr
00641  *
00642  * Get the underlying pointer for ruby object +val+ and return it as a
00643  * Fiddle::Pointer object.
00644  */
00645 static VALUE
00646 rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
00647 {
00648     VALUE ptr, wrap = val, vptr;
00649 
00650     if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
00651         rb_io_t *fptr;
00652         FILE *fp;
00653         GetOpenFile(val, fptr);
00654         fp = rb_io_stdio_file(fptr);
00655         ptr = rb_fiddle_ptr_new(fp, 0, NULL);
00656     }
00657     else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
00658         char *str = StringValuePtr(val);
00659         ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
00660     }
00661     else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
00662         if (rb_obj_is_kind_of(vptr, rb_cPointer)){
00663             ptr = vptr;
00664             wrap = 0;
00665         }
00666         else{
00667             rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
00668         }
00669     }
00670     else{
00671         VALUE num = rb_Integer(val);
00672         if (num == val) wrap = 0;
00673         ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
00674     }
00675     OBJ_INFECT(ptr, val);
00676     if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
00677     return ptr;
00678 }
00679 
00680 void
00681 Init_fiddle_pointer(void)
00682 {
00683     id_to_ptr = rb_intern("to_ptr");
00684 
00685     /* Document-class: Fiddle::Pointer
00686      *
00687      * Fiddle::Pointer is a class to handle C pointers
00688      *
00689      */
00690     rb_cPointer = rb_define_class_under(mFiddle, "Pointer", rb_cObject);
00691     rb_define_alloc_func(rb_cPointer, rb_fiddle_ptr_s_allocate);
00692     rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
00693     rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
00694     rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
00695     rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
00696     rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
00697     rb_define_method(rb_cPointer, "free",  rb_fiddle_ptr_free_get, 0);
00698     rb_define_method(rb_cPointer, "to_i",  rb_fiddle_ptr_to_i, 0);
00699     rb_define_method(rb_cPointer, "to_int",  rb_fiddle_ptr_to_i, 0);
00700     rb_define_method(rb_cPointer, "to_value",  rb_fiddle_ptr_to_value, 0);
00701     rb_define_method(rb_cPointer, "ptr",   rb_fiddle_ptr_ptr, 0);
00702     rb_define_method(rb_cPointer, "+@", rb_fiddle_ptr_ptr, 0);
00703     rb_define_method(rb_cPointer, "ref",   rb_fiddle_ptr_ref, 0);
00704     rb_define_method(rb_cPointer, "-@", rb_fiddle_ptr_ref, 0);
00705     rb_define_method(rb_cPointer, "null?", rb_fiddle_ptr_null_p, 0);
00706     rb_define_method(rb_cPointer, "to_s", rb_fiddle_ptr_to_s, -1);
00707     rb_define_method(rb_cPointer, "to_str", rb_fiddle_ptr_to_str, -1);
00708     rb_define_method(rb_cPointer, "inspect", rb_fiddle_ptr_inspect, 0);
00709     rb_define_method(rb_cPointer, "<=>", rb_fiddle_ptr_cmp, 1);
00710     rb_define_method(rb_cPointer, "==", rb_fiddle_ptr_eql, 1);
00711     rb_define_method(rb_cPointer, "eql?", rb_fiddle_ptr_eql, 1);
00712     rb_define_method(rb_cPointer, "+", rb_fiddle_ptr_plus, 1);
00713     rb_define_method(rb_cPointer, "-", rb_fiddle_ptr_minus, 1);
00714     rb_define_method(rb_cPointer, "[]", rb_fiddle_ptr_aref, -1);
00715     rb_define_method(rb_cPointer, "[]=", rb_fiddle_ptr_aset, -1);
00716     rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
00717     rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
00718 
00719     /*  Document-const: NULL
00720      *
00721      * A NULL pointer
00722      */
00723     rb_define_const(mFiddle, "NULL", rb_fiddle_ptr_new(0, 0, 0));
00724 }
00725