summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/AbstractMemory.c11
-rw-r--r--lib/ffi/ffi.rb2
-rw-r--r--lib/ffi/platform.rb2
-rw-r--r--lib/ffi/struct.rb263
-rw-r--r--samples/gettimeofday.rb12
5 files changed, 283 insertions, 7 deletions
diff --git a/ext/AbstractMemory.c b/ext/AbstractMemory.c
index a9be9f8..2fb7ef1 100644
--- a/ext/AbstractMemory.c
+++ b/ext/AbstractMemory.c
@@ -63,11 +63,12 @@ memory_get_array_of_##name(VALUE self, VALUE offset, VALUE length) \
return retVal; \
}
-#define INT(type, toNative, fromNative) NUM_OP(type, type##_t, toNative, fromNative); \
- NUM_OP(u##type, u_##type##_t, toNative, fromNative)
-INT(int8, NUM2INT, INT2FIX);
-INT(int16, NUM2INT, INT2FIX);
-INT(int32, NUM2INT, INT2FIX);
+NUM_OP(int8, int8_t, NUM2INT, INT2NUM);
+NUM_OP(uint8, u_int8_t, NUM2UINT, UINT2NUM);
+NUM_OP(int16, int16_t, NUM2INT, INT2NUM);
+NUM_OP(uint16, u_int16_t, NUM2UINT, UINT2NUM);
+NUM_OP(int32, int32_t, NUM2INT, INT2NUM);
+NUM_OP(uint32, u_int32_t, NUM2UINT, UINT2NUM);
NUM_OP(int64, int64_t, NUM2LL, LL2NUM);
NUM_OP(uint64, u_int64_t, NUM2ULL, ULL2NUM);
NUM_OP(float32, float, NUM2DBL, rb_float_new);
diff --git a/lib/ffi/ffi.rb b/lib/ffi/ffi.rb
index e9a1aa8..1d8cd1a 100644
--- a/lib/ffi/ffi.rb
+++ b/lib/ffi/ffi.rb
@@ -52,9 +52,9 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'ffi.so'
-puts "Loading ffi/platform"
require 'ffi/platform'
require 'ffi/memorypointer'
+require 'ffi/struct'
module FFI
# Specialised error classes
diff --git a/lib/ffi/platform.rb b/lib/ffi/platform.rb
index f10e0f3..cc86d40 100644
--- a/lib/ffi/platform.rb
+++ b/lib/ffi/platform.rb
@@ -5,7 +5,6 @@ module FFI
OS =~ /#{os}/ ? true : false
end
public
- puts "Platform ruby init"
NAME = "#{ARCH}-#{OS}"
IS_LINUX = is_os("linux")
IS_MAC = is_os("darwin")
@@ -21,5 +20,6 @@ module FFI
when /(linux|.*bsd)/
'.so'
end
+
end
end \ No newline at end of file
diff --git a/lib/ffi/struct.rb b/lib/ffi/struct.rb
new file mode 100644
index 0000000..b9bc240
--- /dev/null
+++ b/lib/ffi/struct.rb
@@ -0,0 +1,263 @@
+require 'ffi/platform'
+module FFI
+ class StructLayout
+ def initialize(fields, size)
+ @fields = fields
+ @size = size
+ end
+
+ def [](name)
+ @fields[name]
+ end
+ def size
+ @size
+ end
+ end
+ class StructLayoutBuilder
+ LONG_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::LONG_SIZE
+ ADDRESS_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
+ FLOAT_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
+ DOUBLE_ALIGN = Platform::ARCH =~ /sparc.*/ ? 64 : Platform::ADDRESS_SIZE
+ class Field
+ def initialize(off)
+ @off = off
+ end
+
+ def offset
+ @off
+ end
+ def size
+ self.size
+ end
+ def align
+ self.align
+ end
+ def self.align
+ self.size
+ end
+ end
+ class Signed8 < Field
+ def self.size; 8; end
+ def set(ptr, val)
+ ptr.set_int8(@off, val)
+ end
+ def get(ptr)
+ ptr.get_int8(@off)
+ end
+ end
+ class Unsigned8 < Field
+ def self.size; 8; end
+ def set(ptr, val)
+ ptr.set_uint8(@off, val)
+ end
+ def get(ptr)
+ ptr.get_uint8(@off)
+ end
+ end
+ class Signed16 < Field
+ def self.size; 16; end
+ def set(ptr, val)
+ ptr.set_int16(@off, val)
+ end
+ def get(ptr)
+ ptr.get_int16(@off)
+ end
+ end
+ class Unsigned16 < Field
+ def self.size; 16; end
+ def set(ptr, val)
+ ptr.set_uint16(@off, val)
+ end
+ def get(ptr)
+ ptr.get_uint16(@off)
+ end
+ end
+ class Signed32 < Field
+ def self.size; 32; end
+ def set(ptr, val)
+ ptr.set_int32(@off, val)
+ end
+ def get(ptr)
+ ptr.get_int32(@off)
+ end
+ end
+ class Unsigned32 < Field
+ def self.size; 32; end
+ def set(ptr, val)
+ ptr.set_uint32(@off, val)
+ end
+ def get(ptr)
+ ptr.get_uint32(@off)
+ end
+ end
+ class Signed64 < Field
+ def self.size; 64; end
+ def self.align; LONG_ALIGN; end
+ def set(ptr, val)
+ ptr.set_int64(@off, val)
+ end
+ def get(ptr)
+ ptr.get_int64(@off)
+ end
+ end
+ class Unsigned64 < Field
+ def self.size; 64; end
+ def self.align; LONG_ALIGN; end
+ def set(ptr, val)
+ ptr.set_uint64(@off, val)
+ end
+ def get(ptr)
+ ptr.get_uint64(@off)
+ end
+ end
+ def initialize
+ @fields = {}
+ @size = 0
+ end
+ def add_field(name, type, offset=nil)
+ field_class = case type
+ when :char, NativeType::INT8
+ Signed8
+ when :uchar, NativeType::UINT8
+ Unsigned8
+ when :short, NativeType::INT16
+ Signed16
+ when :ushort, NativeType::UINT16
+ Unsigned16
+ when :long, NativeType::LONG
+ FFI::Platform::LONG_SIZE == 32 ? Signed32 : Signed64
+ when :ulong, NativeType::ULONG
+ FFI::Platform::LONG_SIZE == 32 ? Unsigned32 : Unsigned64
+ when :int, NativeType::INT32
+ Signed32
+ when :uint, NativeType::UINT32
+ Unsigned32
+ when :long_long, NativeType::INT64
+ Signed64
+ when :ulong_long, NativeType::UINT64
+ Unsigned64
+ else
+ raise ArgumentError, "Unknown type: #{type}"
+ end
+
+ size = field_class.size / 8
+ off = offset ? offset.to_i : align(@size, field_class.align)
+ @fields[name] = field_class.new(off)
+ @size = off + size
+ end
+ def build
+ StructLayout.new @fields, @size
+ end
+ def align(offset, bits)
+ bytes = bits / 8
+ mask = bytes - 1;
+ off = offset;
+ ((off & mask) != 0) ? (off & ~mask) + bytes : off
+ end
+ end
+ class BaseStruct
+ Buffer = FFI::MemoryPointer
+ attr_reader :pointer
+
+ def initialize(pointer = nil, *spec)
+ @cspec = self.class.layout(*spec)
+
+ if pointer then
+ @pointer = pointer
+ else
+ @pointer = MemoryPointer.new size
+ end
+ end
+ def self.alloc_inout(clear = true)
+ self.new(Buffer.alloc_inout(@size, 1, clear))
+ end
+ def self.alloc_in(clear = true)
+ self.new(Buffer.alloc_in(@size, 1, clear))
+ end
+ def self.alloc_out(clear = true)
+ self.new(Buffer.alloc_out(@size, 1, clear))
+ end
+ def self.size
+ @size
+ end
+ def self.members
+ @layout.members
+ end
+ def size
+ self.class.size
+ end
+ def [](field)
+ @cspec[field].get(@pointer)
+ end
+ def []=(field, val)
+ @cspec[field].put(@pointer, val)
+ end
+ def members
+ @cspec.members
+ end
+ def values
+ @cspec.members.map { |m| self[m] }
+ end
+ def clear
+ @pointer.clear
+ self
+ end
+ end
+ class Struct < BaseStruct
+ def self.jruby_layout(spec)
+ raise "Ruby version not supported" if RUBY_VERSION =~ /1.8.*/
+ builder = FFI::StructLayoutBuilder.new
+ spec[0].each do |name,type|
+ builder.add_field(name, FFI.find_type(type))
+ end
+ builder.build
+ end
+ def self.rubinius_layout(spec)
+ builder = FFI::StructLayoutBuilder.new
+ i = 0
+ while i < spec.size
+ name, type, offset = spec[i, 3]
+
+ code = FFI.find_type(type)
+ builder.add_field(name, code, offset)
+ i += 3
+ end
+ builder.build
+ end
+ def self.layout(*spec)
+
+ return @layout if spec.size == 0
+ cspec = spec[0].kind_of?(Hash) ? jruby_layout(spec) : rubinius_layout(spec)
+
+ @layout = cspec unless self == FFI::Struct
+ @size = cspec.size
+ return cspec
+ end
+ def self.config(base, *fields)
+ config = Config::CONFIG
+ @size = config["#{base}.sizeof"]
+
+ builder = StructLayoutBuilder.new
+
+ fields.each do |field|
+ offset = config["#{base}.#{field}.offset"]
+ size = config["#{base}.#{field}.size"]
+ type = config["#{base}.#{field}.type"]
+ type = type ? type.to_sym : FFI.size_to_type(size)
+
+ code = FFI.find_type type
+ if (code == NativeType::CHAR_ARRAY)
+ builder.add_char_array(field.to_s, size, offset)
+ else
+ builder.add_field(field.to_s, code, offset)
+ end
+ end
+ cspec = builder.build
+
+ @layout = cspec
+ @size = cspec.size if @size < cspec.size
+
+ return cspec
+ end
+ end
+end
diff --git a/samples/gettimeofday.rb b/samples/gettimeofday.rb
new file mode 100644
index 0000000..f9835b4
--- /dev/null
+++ b/samples/gettimeofday.rb
@@ -0,0 +1,12 @@
+require 'ffi'
+class Timeval < FFI::Struct
+# layout :tv_sec => :ulong, :tv_usec => :ulong
+ layout :tv_sec, :ulong, 0, :tv_usec, :ulong, 4
+end
+module LibC
+ extend FFI::Library
+ attach_function :gettimeofday, [ :pointer, :pointer ], :int
+end
+t = Timeval.new
+LibC.gettimeofday(t.pointer, nil)
+puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}"