DEFINITIONS
This source file includes following functions.
1 # -*- ruby -*-
2
3 require 'dl'
4 require 'dl/types'
5
6 module DL
7 module Importable
8 LIB_MAP = {}
9
10 module Internal
11 def init_types()
12 if( !@types )
13 @types = ::DL::Types.new
14 end
15 end
16
17 def init_sym()
18 if( !@SYM )
19 @SYM = {}
20 end
21 end
22
23 def [](name)
24 return @SYM[name.to_s][0]
25 end
26
27 def dlload(*libnames)
28 if( !defined?(@LIBS) )
29 @LIBS = []
30 end
31 libnames.each{|libname|
32 if( !LIB_MAP[libname] )
33 LIB_MAP[libname] = DL.dlopen(libname)
34 end
35 @LIBS.push(LIB_MAP[libname])
36 }
37 end
38 alias dllink :dlload
39
40 def parse_cproto(proto)
41 proto = proto.gsub(/\s+/, " ").strip
42 case proto
43 when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
44 ret = $1
45 args = $2
46 ret = ret.split(/\s+/)
47 args = args.split(/\s*,\s*/)
48 func = ret.pop
49 if( func =~ /^\*/ )
50 func.gsub!(/^\*+/,"")
51 ret.push("*")
52 end
53 ret = ret.join(" ")
54 return [func, ret, args]
55 else
56 raise(RuntimeError,"can't parse the function prototype: #{proto}")
57 end
58 end
59
60 # example:
61 # extern "int strlen(char*)"
62 #
63 def extern(proto)
64 func,ret,args = parse_cproto(proto)
65 return import(func, ret, args)
66 end
67
68 # example:
69 # callback "int method_name(int, char*)"
70 #
71 def callback(proto)
72 func,ret,args = parse_cproto(proto)
73
74 init_types()
75 init_sym()
76
77 rty,_,rdec = @types.encode_type(ret)
78 ty,enc,dec = encode_types(args)
79 symty = rty + ty
80
81 module_eval("module_function :#{func}")
82 sym = module_eval [
83 "DL::callback(\"#{symty}\"){|*args|",
84 " sym,rdec,enc,dec = @SYM['#{func}']",
85 " args = enc.call(args) if enc",
86 " r,rs = #{func}(*args)",
87 " r = rdec.call(r) if rdec",
88 " rs = dec.call(rs) if dec",
89 " @retval = r",
90 " @args = rs",
91 " @retval",
92 "}",
93 ].join("\n")
94
95 @SYM[func] = [sym,rdec,enc,dec]
96
97 return sym
98 end
99
100 # example:
101 # typealias("uint", "unsigned int")
102 #
103 def typealias(*args)
104 init_types()
105 @types.typealias(*args)
106 end
107
108 # example:
109 # symbol "foo_value"
110 # symbol "foo_func", "IIP"
111 #
112 def symbol(name, ty = nil)
113 sym = nil
114 @LIBS.each{|lib|
115 begin
116 if( ty )
117 sym = lib[name, ty]
118 else
119 sym = lib[name]
120 end
121 rescue
122 next
123 end
124 }
125 if( !sym )
126 raise(RuntimeError, "can't find the symbol `#{name}'")
127 end
128 return sym
129 end
130
131 # example:
132 # import("get_length", "int", ["void*", "int"])
133 #
134 def import(name, rettype, argtypes = nil)
135 init_types()
136 init_sym()
137
138 rty,_,rdec = @types.encode_type(rettype)
139 ty,enc,dec = encode_types(argtypes)
140 symty = rty + ty
141
142 sym = symbol(name, symty)
143
144 mname = name.dup
145 if( ?A <= mname[0] && mname[0] <= ?Z )
146 mname[0,1] = mname[0,1].downcase
147 end
148 @SYM[mname] = [sym,rdec,enc,dec]
149
150 module_eval [
151 "def #{mname}(*args)",
152 " sym,rdec,enc,dec = @SYM['#{mname}']",
153 " args = enc.call(args) if enc",
154 if( $DEBUG )
155 " p \"[DL] call #{mname} with \#{args.inspect}\""
156 else
157 ""
158 end,
159 " r,rs = sym.call(*args)",
160 if( $DEBUG )
161 " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\""
162 else
163 ""
164 end,
165 " r = rdec.call(r) if rdec",
166 " rs = dec.call(rs) if dec",
167 " @retval = r",
168 " @args = rs",
169 " return @retval",
170 "end",
171 "module_function :#{mname}",
172 ].join("\n")
173
174 return sym
175 end
176
177 def _args_
178 return @args
179 end
180
181 def _retval_
182 return @retval
183 end
184
185 def encode_types(tys)
186 init_types()
187 encty = []
188 enc = nil
189 dec = nil
190 tys.each_with_index{|ty,idx|
191 ty,c1,c2,_,_ = @types.encode_type(ty)
192 encty.push(ty)
193 if( enc )
194 if( c1 )
195 conv1 = enc
196 enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v}
197 end
198 else
199 if( c1 )
200 enc = proc{|v| v[idx] = c1.call(v[idx]); v}
201 end
202 end
203 if( dec )
204 if( c2 )
205 conv2 = dec
206 dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v}
207 end
208 else
209 if( c2 )
210 dec = proc{|v| v[idx] = c2.call(v[idx]); v}
211 end
212 end
213 }
214 return [encty.join, enc, dec]
215 end
216 end # end of Internal
217 include Internal
218 end # end of Importable
219 end