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