1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
# -*- ruby -*-
require 'dl'
require 'dl/import'
module DL
module Importable
module Internal
def define_struct(contents)
init_types()
Struct.new(@types, contents)
end
alias struct define_struct
def define_union(contents)
init_types()
Union.new(@types, contents)
end
alias union define_union
class Memory
def initialize(ptr, names, ty, len, enc, dec)
@ptr = ptr
@names = names
@ty = ty
@len = len
@enc = enc
@dec = dec
# define methods
@names.each{|name|
instance_eval [
"def #{name}",
" v = @ptr[\"#{name}\"]",
" if( @len[\"#{name}\"] )",
" v = v.collect{|x| @dec[\"#{name}\"] ? @dec[\"#{name}\"].call(x) : x }",
" else",
" v = @dec[\"#{name}\"].call(v) if @dec[\"#{name}\"]",
" end",
" return v",
"end",
"def #{name}=(v)",
" if( @len[\"#{name}\"] )",
" v = v.collect{|x| @enc[\"#{name}\"] ? @enc[\"#{name}\"].call(x) : x }",
" else",
" v = @enc[\"#{name}\"].call(v) if @enc[\"#{name}\"]",
" end",
" @ptr[\"#{name}\"] = v",
" return v",
"end",
].join("\n")
}
end
def to_ptr
return @ptr
end
def size
return @ptr.size
end
end
class Struct
def initialize(types, contents)
@names = []
@ty = {}
@len = {}
@enc = {}
@dec = {}
@size = 0
@tys = ""
@types = types
parse(contents)
end
def size
return @size
end
def members
return @names
end
# ptr must be a PtrData object.
def new(ptr)
ptr.struct!(@tys, *@names)
mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec)
return mem
end
def malloc(size = nil)
if( !size )
size = @size
end
ptr = DL::malloc(size)
return new(ptr)
end
def parse(contents)
contents.each{|elem|
name,ty,num,enc,dec = parse_elem(elem)
@names.push(name)
@ty[name] = ty
@len[name] = num
@enc[name] = enc
@dec[name] = dec
if( num )
@tys += "#{ty}#{num}"
else
@tys += ty
end
}
@size = DL.sizeof(@tys)
end
def parse_elem(elem)
elem.strip!
case elem
when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)$/
ty = ($1 + $2).strip
name = $3
num = nil;
when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)\[(\d+)\]$/
ty = ($1 + $2).strip
name = $3
num = $4.to_i
else
raise(RuntimeError, "invalid element: #{elem}")
end
ty,enc,dec = @types.encode_struct_type(ty)
if( !ty )
raise(TypeError, "unsupported type: #{ty}")
end
return [name,ty,num,enc,dec]
end
end # class Struct
class Union < Struct
def new
ptr = DL::malloc(@size)
ptr.union!(@tys, *@names)
mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec)
return mem
end
end
end # module Internal
end # module Importable
end # module DL
|