123456789_123456789_123456789_123456789_123456789_

Class: Fiddle::Pointer

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, FFI::DataConverter
Inherits: Object
Defined in: ext/fiddle/pointer.c,
ext/fiddle/lib/fiddle/ffi_backend.rb

Overview

Pointer is a class to handle C pointers

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(address) ⇒ fiddle_cptr .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.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 216

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);
	}
	RB_OBJ_WRITE(self, &data->wrap[0], wrap);
	RB_OBJ_WRITE(self, &data->wrap[1], funcwrap);
	data->ptr  = p;
	data->size = s;
	data->free = f;
    }

    return Qnil;
}

#initialize(addr, size = nil, free = nil) ⇒ Pointer

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 291

def initialize(addr, size = nil, free = nil)
  ptr = if addr.is_a?(FFI::Pointer)
          addr

        elsif addr.is_a?(Integer)
          FFI::Pointer.new(addr)

        elsif addr.respond_to?(:to_ptr)
          fiddle_ptr = addr.to_ptr
          if fiddle_ptr.is_a?(Pointer)
            fiddle_ptr.ffi_ptr
          elsif fiddle_ptr.is_a?(FFI::AutoPointer)
            addr.ffi_ptr
          elsif fiddle_ptr.is_a?(FFI::Pointer)
            fiddle_ptr
          else
            raise DLError.new("to_ptr should return a Fiddle::Pointer object, was #{fiddle_ptr.class}")
          end
        elsif addr.is_a?(IO)
          raise NotImplementedError, "IO ptr isn't supported"
        end

  @size = size ? size : ptr.size
  @free = free
  @ffi_ptr = ptr
  @freed = false
end

Class Method Details

.[](value) Also known as: .to_ptr

call-seq:

Fiddle::Pointer[val]         => cptr
to_ptr(val)  => cptr

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 772

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) RB_OBJ_WRITE(ptr, &RPTR_DATA(ptr)->wrap[0], wrap);
    return ptr;
}

.from_native(value, ctx)

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 235

def self.from_native(value, ctx)
  self.new(value)
end

.malloc(size, free = nil)

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 327

def self.malloc(size, free = nil)
  if block_given? and free.nil?
    message = "a free function must be supplied to #{self}.malloc " +
              "when it is called with a block"
    raise ArgumentError, message
  end

  pointer = new(LibC.malloc(size), size, free)
  if block_given?
    begin
      yield(pointer)
    ensure
      pointer.call_free
    end
  else
    pointer
  end
end

.read(address, len) ⇒ String

Or read the memory at address address with length len and return a string with that memory

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 815

static VALUE
rb_fiddle_ptr_read_mem(VALUE klass, VALUE address, VALUE len)
{
    return rb_str_new((char *)NUM2PTR(address), NUM2ULONG(len));
}

.to_native(value, ctx)

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 223

def self.to_native(value, ctx)
  if value.is_a?(Pointer)
    value.ffi_ptr

  elsif value.is_a?(Integer)
    FFI::Pointer.new(value)

  elsif value.is_a?(String)
    value
  end
end

Fiddle::Pointercptr .to_ptr(val) ⇒ cptr
Also known as: .[]

Alias for .[].

.write(address, str)

Write bytes in str to the location pointed to by address.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 827

static VALUE
rb_fiddle_ptr_write_mem(VALUE klass, VALUE addr, VALUE str)
{
    memcpy(NUM2PTR(addr), StringValuePtr(str), RSTRING_LEN(str));
    return str;
}

Instance Attribute Details

#ffi_ptr (readonly)

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 219

attr_reader :ffi_ptr

#freeFiddle::Function (rw)

Get the free function for this pointer.

Returns a new instance of Function.

See Function.new

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 435

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) (rw)

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 415

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?Boolean (readonly)

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 476

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

#null?Boolean (readonly)

Returns true if this is a null pointer.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 400

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

#size (rw)

Get the size of this pointer.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 758

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

#size=(size) (rw)

Set the size of this pointer to #size

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 746

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

Instance Method Details

#+(n) ⇒ new cptr

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 626

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

#+@ Also known as: #ptr

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

Analogous to the star operator in C.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 369

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

#-(n) ⇒ new cptr

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 644

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

#-@ Also known as: #ref

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

Analogous to the ampersand operator in C.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 386

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

#<=>(other) ⇒ 1, ...

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

Returns nil if #ptr cannot be compared to other.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 605

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

#==(other) ⇒ Boolean #eql?(other) ⇒ Boolean
Also known as: #eql?

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 584

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

#[](index) ⇒ Integer #[](start, length) ⇒ String

Returns integer stored at index.

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 666

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

#[]=(index, int) ⇒ Integer #[]=(start, length, string or cptr or addr) ⇒ String, ...

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.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 703

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_freenil

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 462

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

#==(other) ⇒ Boolean #eql?(other) ⇒ Boolean

Alias for #==.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 870

def eql?(other)
  return unless other.is_a?(Pointer)
  self.to_i == other.to_i
end

#inspect

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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 566

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 *)(VALUE)data->free);
}

#+@ #ptr

Alias for #+@.

#-@ #ref

Alias for #-@.

#to_iInteger Also known as: #to_int

Returns the integer memory location of this pointer.

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 339

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_int

Alias for #to_i.

#to_ptr

[ GitHub ]

  
# File 'ext/fiddle/lib/fiddle/ffi_backend.rb', line 350

def to_ptr
  @ffi_ptr
end

#to_sString #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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 499

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_strString #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

[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 537

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 ⇒ ?

Cast this pointer to a ruby object.

Raises:

  • (NotImplementedError)
[ GitHub ]

  
# File 'ext/fiddle/pointer.c', line 353

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