# class Fiddle::Pointer

`Fiddle::Pointer` is a class to handle C pointers

### Public Class Methods

Fiddle::Pointer[val] → cptr click to toggle source
to_ptr(val) → cptr

Get the underlying pointer for ruby object `val` and return it as a `Fiddle::Pointer` object.

    static VALUE
    rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
    {
        VALUE ptr, wrap = val, vptr;

        if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
            rb_io_t *fptr;
            FILE *fp;
            GetOpenFile(val, fptr);
            fp = rb_io_stdio_file(fptr);
            ptr = rb_fiddle_ptr_new(fp, 0, NULL);
        }
        else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
            char *str = StringValuePtr(val);
            ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
        }
        else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
            if (rb_obj_is_kind_of(vptr, rb_cPointer)){
                ptr = vptr;
                wrap = 0;
            }
            else{
                rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
            }
        }
        else{
            VALUE num = rb_Integer(val);
            if (num == val) wrap = 0;
            ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
        }
        OBJ_INFECT(ptr, val);
        if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
        return ptr;
    }

Fiddle::Pointer.malloc(size, freefunc = nil) → fiddle pointer instance click to toggle source

Allocate `size` bytes of memory and associate it with an optional `freefunc` that will be called when the pointer is garbage collected.

`freefunc` must be an address pointing to a function or an instance of `Fiddle::Function`

    static VALUE
    rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
    {
        VALUE size, sym, obj, wrap = 0;
        long s;
        freefunc_t f;

        switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
          case 1:
            s = NUM2LONG(size);
            f = NULL;
            break;
          case 2:
            s = NUM2LONG(size);
            f = get_freefunc(sym, &wrap);
            break;
          default:
            rb_bug("rb_fiddle_ptr_s_malloc");
        }

        obj = rb_fiddle_ptr_malloc(s,f);
        if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;

        return obj;
    }

Fiddle::Pointer.new(address) → fiddle_cptr click to toggle source
new(address, size) → fiddle_cptr
new(address, size, freefunc) → fiddle_cptr

Create a new pointer to `address` with an optional `size` and `freefunc`.

`freefunc` will be called when the instance is garbage collected.

    static VALUE
    rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
    {
        VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
        struct ptr_data *data;
        void *p = NULL;
        freefunc_t f = NULL;
        long s = 0;

        if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
            VALUE addrnum = rb_Integer(ptr);
            if (addrnum != ptr) wrap = ptr;
            p = NUM2PTR(addrnum);
        }
        if (argc >= 2) {
            s = NUM2LONG(size);
        }
        if (argc >= 3) {
            f = get_freefunc(sym, &funcwrap);
        }

        if (p) {
            TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
            if (data->ptr && data->free) {
                /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
                (*(data->free))(data->ptr);
            }
            data->wrap[0] = wrap;
            data->wrap[1] = funcwrap;
            data->ptr  = p;
            data->size = s;
            data->free = f;
        }

        return Qnil;
    }

to_ptr(val) → cptr click to toggle source

Get the underlying pointer for ruby object `val` and return it as a `Fiddle::Pointer` object.

    static VALUE
    rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
    {
        VALUE ptr, wrap = val, vptr;

        if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
            rb_io_t *fptr;
            FILE *fp;
            GetOpenFile(val, fptr);
            fp = rb_io_stdio_file(fptr);
            ptr = rb_fiddle_ptr_new(fp, 0, NULL);
        }
        else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
            char *str = StringValuePtr(val);
            ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
        }
        else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
            if (rb_obj_is_kind_of(vptr, rb_cPointer)){
                ptr = vptr;
                wrap = 0;
            }
            else{
                rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
            }
        }
        else{
            VALUE num = rb_Integer(val);
            if (num == val) wrap = 0;
            ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
        }
        OBJ_INFECT(ptr, val);
        if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
        return ptr;
    }

### Public Instance Methods

ptr + n → new cptr click to toggle source

Returns a new pointer instance that has been advanced `n` bytes.

    static VALUE
    rb_fiddle_ptr_plus(VALUE self, VALUE other)
    {
        void *ptr;
        long num, size;

        ptr = rb_fiddle_ptr2cptr(self);
        size = RPTR_DATA(self)->size;
        num = NUM2LONG(other);
        return rb_fiddle_ptr_new((char *)ptr + num, size - num, 0);
    }

ptr click to toggle source

Returns a new `Fiddle::Pointer` instance that is a dereferenced pointer for this pointer.

Analogous to the star operator in C.

    static VALUE
    rb_fiddle_ptr_ptr(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
    }

ptr - n → new cptr click to toggle source

Returns a new pointer instance that has been moved back `n` bytes.

    static VALUE
    rb_fiddle_ptr_minus(VALUE self, VALUE other)
    {
        void *ptr;
        long num, size;

        ptr = rb_fiddle_ptr2cptr(self);
        size = RPTR_DATA(self)->size;
        num = NUM2LONG(other);
        return rb_fiddle_ptr_new((char *)ptr - num, size + num, 0);
    }

ref click to toggle source

Returns a new `Fiddle::Pointer` instance that is a reference pointer for this pointer.

Analogous to the ampersand operator in C.

    static VALUE
    rb_fiddle_ptr_ref(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return rb_fiddle_ptr_new(&(data->ptr),0,0);
    }

ptr <=> other → -1, 0, 1, or nil click to toggle source

Returns -1 if less than, 0 if equal to, 1 if greater than `other`.

Returns nil if `ptr` cannot be compared to `other`.

    static VALUE
    rb_fiddle_ptr_cmp(VALUE self, VALUE other)
    {
        void *ptr1, *ptr2;
        SIGNED_VALUE diff;

        if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qnil;

        ptr1 = rb_fiddle_ptr2cptr(self);
        ptr2 = rb_fiddle_ptr2cptr(other);
        diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
        if (!diff) return INT2FIX(0);
        return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
    }

ptr == other → true or false click to toggle source

Returns true if `other` wraps the same pointer, otherwise returns false.

    static VALUE
    rb_fiddle_ptr_eql(VALUE self, VALUE other)
    {
        void *ptr1, *ptr2;

        if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;

        ptr1 = rb_fiddle_ptr2cptr(self);
        ptr2 = rb_fiddle_ptr2cptr(other);

        return ptr1 == ptr2 ? Qtrue : Qfalse;
    }

ptr[index] → an_integer click to toggle source
ptr[start, length] → a_string

Returns integer stored at index.

If start and length are given, a string containing the bytes from start of length will be returned.

    static VALUE
    rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
    {
        VALUE arg0, arg1;
        VALUE retval = Qnil;
        size_t offset, len;
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
        switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
          case 1:
            offset = NUM2ULONG(arg0);
            retval = INT2NUM(*((char *)data->ptr + offset));
            break;
          case 2:
            offset = NUM2ULONG(arg0);
            len    = NUM2ULONG(arg1);
            retval = rb_tainted_str_new((char *)data->ptr + offset, len);
            break;
          default:
            rb_bug("rb_fiddle_ptr_aref()");
        }
        return retval;
    }

ptr[index] = int → int click to toggle source
ptr[start, length] = string or cptr or addr → string or dl_cptr or addr

`Set` the value at `index` to `int`.

Or, set the memory at `start` until `length` with the contents of `string`, the memory from `dl_cptr`, or the memory pointed at by the memory address `addr`.

    static VALUE
    rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
    {
        VALUE arg0, arg1, arg2;
        VALUE retval = Qnil;
        size_t offset, len;
        void *mem;
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
        switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
          case 2:
            offset = NUM2ULONG(arg0);
            ((char*)data->ptr)[offset] = NUM2UINT(arg1);
            retval = arg1;
            break;
          case 3:
            offset = NUM2ULONG(arg0);
            len    = NUM2ULONG(arg1);
            if (RB_TYPE_P(arg2, T_STRING)) {
                mem = StringValuePtr(arg2);
            }
            else if( rb_obj_is_kind_of(arg2, rb_cPointer) ){
                mem = rb_fiddle_ptr2cptr(arg2);
            }
            else{
                mem    = NUM2PTR(arg2);
            }
            memcpy((char *)data->ptr + offset, mem, len);
            retval = arg2;
            break;
          default:
            rb_bug("rb_fiddle_ptr_aset()");
        }
        return retval;
    }

eql?(other) → true or false click to toggle source

Returns true if `other` wraps the same pointer, otherwise returns false.

    static VALUE
    rb_fiddle_ptr_eql(VALUE self, VALUE other)
    {
        void *ptr1, *ptr2;

        if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;

        ptr1 = rb_fiddle_ptr2cptr(self);
        ptr2 = rb_fiddle_ptr2cptr(other);

        return ptr1 == ptr2 ? Qtrue : Qfalse;
    }

free → Fiddle::Function click to toggle source

Get the free function for this pointer.

Returns a new instance of `Fiddle::Function`.

See `Fiddle::Function.new`

    static VALUE
    rb_fiddle_ptr_free_get(VALUE self)
    {
        struct ptr_data *pdata;
        VALUE address;
        VALUE arg_types;
        VALUE ret_type;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);

        if (!pdata->free)
            return Qnil;

        address = PTR2NUM(pdata->free);
        ret_type = INT2NUM(TYPE_VOID);
        arg_types = rb_ary_new();
        rb_ary_push(arg_types, INT2NUM(TYPE_VOIDP));

        return rb_fiddle_new_function(address, arg_types, ret_type);
    }

free=(function) click to toggle source

`Set` the free function for this pointer to `function` in the given `Fiddle::Function`.

    static VALUE
    rb_fiddle_ptr_free_set(VALUE self, VALUE val)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        data->free = get_freefunc(val, &data->wrap[1]);

        return Qnil;
    }

inspect click to toggle source

Returns a string formatted with an easily readable representation of the internal state of the pointer.

    static VALUE
    rb_fiddle_ptr_inspect(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
                          RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
    }

null? click to toggle source

Returns `true` if this is a null pointer.

    static VALUE
    rb_fiddle_ptr_null_p(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return data->ptr ? Qfalse : Qtrue;
    }

ptr click to toggle source

Returns a new `Fiddle::Pointer` instance that is a dereferenced pointer for this pointer.

Analogous to the star operator in C.

    static VALUE
    rb_fiddle_ptr_ptr(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
    }

ref click to toggle source

Returns a new `Fiddle::Pointer` instance that is a reference pointer for this pointer.

Analogous to the ampersand operator in C.

    static VALUE
    rb_fiddle_ptr_ref(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return rb_fiddle_ptr_new(&(data->ptr),0,0);
    }

size click to toggle source

Get the size of this pointer.

    static VALUE
    rb_fiddle_ptr_size_get(VALUE self)
    {
        return LONG2NUM(RPTR_DATA(self)->size);
    }

size=(size) click to toggle source

`Set` the size of this pointer to `size`

    static VALUE
    rb_fiddle_ptr_size_set(VALUE self, VALUE size)
    {
        RPTR_DATA(self)->size = NUM2LONG(size);
        return size;
    }

to_i click to toggle source

Returns the integer memory location of this pointer.

    static VALUE
    rb_fiddle_ptr_to_i(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return PTR2NUM(data->ptr);
    }

to_i click to toggle source

Returns the integer memory location of this pointer.

    static VALUE
    rb_fiddle_ptr_to_i(VALUE self)
    {
        struct ptr_data *data;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return PTR2NUM(data->ptr);
    }

to_s → string click to toggle source
to_s(len) → string

Returns the pointer contents as a string.

When called with no arguments, this method will return the contents until the first NULL byte.

When called with `len`, a string of `len` bytes will be returned.

See `to_str`

    static VALUE
    rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
    {
        struct ptr_data *data;
        VALUE arg1, val;
        int len;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        switch (rb_scan_args(argc, argv, "01", &arg1)) {
          case 0:
            val = rb_tainted_str_new2((char*)(data->ptr));
            break;
          case 1:
            len = NUM2INT(arg1);
            val = rb_tainted_str_new((char*)(data->ptr), len);
            break;
          default:
            rb_bug("rb_fiddle_ptr_to_s");
        }

        return val;
    }

to_str → string click to toggle source
to_str(len) → string

Returns the pointer contents as a string.

When called with no arguments, this method will return the contents with the length of this pointer's `size`.

When called with `len`, a string of `len` bytes will be returned.

See `to_s`

    static VALUE
    rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
    {
        struct ptr_data *data;
        VALUE arg1, val;
        int len;

        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        switch (rb_scan_args(argc, argv, "01", &arg1)) {
          case 0:
            val = rb_tainted_str_new((char*)(data->ptr),data->size);
            break;
          case 1:
            len = NUM2INT(arg1);
            val = rb_tainted_str_new((char*)(data->ptr), len);
            break;
          default:
            rb_bug("rb_fiddle_ptr_to_str");
        }

        return val;
    }

to_value click to toggle source

Cast this pointer to a ruby object.

    static VALUE
    rb_fiddle_ptr_to_value(VALUE self)
    {
        struct ptr_data *data;
        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
        return (VALUE)(data->ptr);
    }