summaryrefslogtreecommitdiff
path: root/ext/dl/lib/dl/struct.rb
diff options
context:
space:
mode:
authorttate <ttate@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-02-04 13:35:37 +0000
committerttate <ttate@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2005-02-04 13:35:37 +0000
commitbda37095ca990568069aaf07dc6b3fa8ceebc327 (patch)
tree15043d94698579d6ab19544542479a42385cd1b5 /ext/dl/lib/dl/struct.rb
parent4ae9132605dc7b0297bcda408ca7a2ad7de39d2f (diff)
added new files.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7883 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/dl/lib/dl/struct.rb')
-rw-r--r--ext/dl/lib/dl/struct.rb203
1 files changed, 203 insertions, 0 deletions
diff --git a/ext/dl/lib/dl/struct.rb b/ext/dl/lib/dl/struct.rb
new file mode 100644
index 0000000000..5c0775277e
--- /dev/null
+++ b/ext/dl/lib/dl/struct.rb
@@ -0,0 +1,203 @@
+require 'dl'
+require 'dl/pack.rb'
+
+module DL
+ class CStruct
+ def CStruct.entity_class()
+ CStructEntity
+ end
+ end
+
+ class CUnion
+ def CUnion.entity_class()
+ CUnionEntity
+ end
+ end
+
+ module CStructBuilder
+ def create(klass, types, members)
+ new_class = Class.new(klass){
+ entity = nil
+ define_method(:initialize){|addr|
+ entity = klass.entity_class.new(addr, types)
+ entity.assign_names(members)
+ }
+ define_method(:to_ptr){ entity }
+ define_method(:to_i){ entity.to_i }
+ members.each{|name|
+ define_method(name){ entity[name] }
+ define_method(name + "="){|val| entity[name] = val }
+ }
+ }
+ size = klass.entity_class.size(types)
+ new_class.module_eval(<<-EOS)
+ def new_class.size()
+ #{size}
+ end
+ def new_class.malloc()
+ addr = DL.malloc(#{size})
+ new(addr)
+ end
+ EOS
+ return new_class
+ end
+ module_function :create
+ end
+
+ class CStructEntity < CPtr
+ include PackInfo
+ include ValueUtil
+
+ def CStructEntity.malloc(types, func = nil)
+ addr = DL.malloc(CStructEntity.size(types))
+ CStructEntity.new(addr, types, func)
+ end
+
+ def CStructEntity.size(types)
+ offset = 0
+ types.each_with_index{|t,i|
+ orig_offset = offset
+ if( t.is_a?(Array) )
+ offset = PackInfo.align(orig_offset, PackInfo::ALIGN_MAP[TYPE_VOIDP])
+ size = offset - orig_offset
+ offset += (PackInfo::SIZE_MAP[t[0]] * t[1])
+ else
+ offset = PackInfo.align(orig_offset, PackInfo::ALIGN_MAP[t])
+ size = offset - orig_offset
+ offset += PackInfo::SIZE_MAP[t]
+ end
+ }
+ offset = PackInfo.align(offset, PackInfo::ALIGN_MAP[TYPE_VOIDP])
+ offset
+ end
+
+ def initialize(addr, types, func = nil)
+ set_ctypes(types)
+ super(addr, @size, func)
+ end
+
+ def assign_names(members)
+ @members = members
+ end
+
+ def set_ctypes(types)
+ @ctypes = types
+ @offset = []
+ offset = 0
+ types.each_with_index{|t,i|
+ orig_offset = offset
+ if( t.is_a?(Array) )
+ offset = align(orig_offset, ALIGN_MAP[TYPE_VOIDP])
+ else
+ offset = align(orig_offset, ALIGN_MAP[t])
+ end
+ size = offset - orig_offset
+ @offset[i] = offset
+ if( t.is_a?(Array) )
+ offset += (SIZE_MAP[t[0]] * t[1])
+ else
+ offset += SIZE_MAP[t]
+ end
+ }
+ offset = align(offset, ALIGN_MAP[TYPE_VOIDP])
+ @size = offset
+ end
+
+ def [](name)
+ idx = @members.index(name)
+ if( idx.nil? )
+ raise(ArgumentError, "no such member: #{name}")
+ end
+ ty = @ctypes[idx]
+ if( ty.is_a?(Array) )
+ r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
+ else
+ r = super(@offset[idx], SIZE_MAP[ty.abs])
+ end
+ packer = Packer.new([ty])
+ val = packer.unpack([r])
+ case ty
+ when Array
+ case ty[0]
+ when TYPE_VOIDP
+ val = val.collect{|v| CPtr.new(v)}
+ end
+ when TYPE_VOIDP
+ val = CPtr.new(val[0])
+ else
+ val = val[0]
+ end
+ if( ty.is_a?(Integer) && (ty < 0) )
+ return unsigned_value(val, ty)
+ elsif( ty.is_a?(Array) && (ty[0] < 0) )
+ return val.collect{|v| unsigned_value(v,ty[0])}
+ else
+ return val
+ end
+ end
+
+ def []=(name, val)
+ idx = @members.index(name)
+ if( idx.nil? )
+ raise(ArgumentError, "no such member: #{name}")
+ end
+ ty = @ctypes[idx]
+ packer = Packer.new([ty])
+ val = wrap_arg(val, ty, [])
+ buff = packer.pack([val].flatten())
+ super(@offset[idx], buff.size, buff)
+ if( ty.is_a?(Integer) && (ty < 0) )
+ return unsigned_value(val, ty)
+ elsif( ty.is_a?(Array) && (ty[0] < 0) )
+ return val.collect{|v| unsigned_value(v,ty[0])}
+ else
+ return val
+ end
+ end
+
+ def to_s()
+ super(@size)
+ end
+ end
+
+ class CUnionEntity < CStruct
+ include PackInfo
+
+ def CUnionEntity.malloc(types)
+ addr = DL.malloc(CUnionEntity.size(types))
+ CUnionEntity.new(addr, types, func)
+ end
+
+ def CUnionEntity.size(types)
+ size = 0
+ types.each_with_index{|t,i|
+ if( t.is_a?(Array) )
+ tsize = PackInfo::SIZE_MAP[t[0]] * t[1]
+ else
+ tsize = PackInfo::SIZE_MAP[t]
+ end
+ if( tsize > size )
+ size = tsize
+ end
+ }
+ end
+
+ def set_ctypes(types)
+ @ctypes = types
+ @offset = []
+ @size = 0
+ types.each_with_index{|t,i|
+ @offset[i] = 0
+ if( t.is_a?(Array) )
+ size = SIZE_MAP[t[0]] * t[1]
+ else
+ size = SIZE_MAP[t]
+ end
+ if( size > @size )
+ @size = size
+ end
+ }
+ end
+ end
+end
+