class Fiddle::Pointer - Documentation for Ruby 3.2

# 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);
            wrap = 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_eFiddleDLError, "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);
        }
        if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
        return ptr;
    }

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

## Examples¶ ↑

    # Automatically freeing the pointer when the block is exited - recommended
    Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
      ...
    end

    # Manually freeing but relying on the garbage collector otherwise
    pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
    ...
    pointer.call_free

    # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
    pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
    ...

    # Only manually freeing
    pointer = Fiddle::Pointer.malloc(size)
    begin
      ...
    ensure
      Fiddle.free pointer
    end

    # No free function and no call to free - the native memory will leak if the pointer is garbage collected
    pointer = Fiddle::Pointer.malloc(size)
    ...

Allocate `size` bytes of memory and associate it with an optional `freefunc`.

If a block is supplied, the pointer will be yielded to the block instead of being returned, and the return value of the block will be returned. A `freefunc` must be supplied if a block is.

If a `freefunc` is supplied it will be called once, when the pointer is garbage collected or when the block is left if a block is supplied or when the user calls `call_free`, whichever happens first. `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(klass, s,f);
        if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;

        if (rb_block_given_p()) {
            if (!f) {
                rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
            }
            return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
        } else {
            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;
    }

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);
            wrap = 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_eFiddleDLError, "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);
        }
        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

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

Analogous to the star operator in C.

Alias for: ptr
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

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

Analogous to the ampersand operator in C.

Alias for: ref
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;
    }

Also aliased as: eql?
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_eFiddleDLError, "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_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_eFiddleDLError, "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;
    }

call_free → nil click to toggle source

Call the free function for this pointer. Calling more than once will do nothing. Does nothing if there is no free function attached.

    static VALUE
    rb_fiddle_ptr_call_free(VALUE self)
    {
        struct ptr_data *pdata;
        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
        fiddle_ptr_free_ptr(pdata);
        return Qnil;
    }

eql?(other) → true or false

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

Alias for: ==
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;
    }

freed? → bool click to toggle source

Returns if the free function for this pointer has been called.

    static VALUE
    rb_fiddle_ptr_freed_p(VALUE self)
    {
        struct ptr_data *pdata;
        TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
        return pdata->freed ? Qtrue : Qfalse;
    }

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);
    }

Also aliased as: +@
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);
    }

Also aliased as: -@
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);
    }

Also aliased as: to_int
to_i

Returns the integer memory location of this pointer.

Alias for: to_i
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_str_new2((char*)(data->ptr));
            break;
          case 1:
            len = NUM2INT(arg1);
            val = rb_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_str_new((char*)(data->ptr),data->size);
            break;
          case 1:
            len = NUM2INT(arg1);
            val = rb_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);
    }