source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/dl/import.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 4.5 KB
Line 
1# -*- ruby -*-
2
3require 'dl'
4require 'dl/types'
5
6module DL
7 module Importable
8 LIB_MAP = {}
9
10 module Internal
11 def init_types()
12 @types ||= ::DL::Types.new
13 end
14
15 def init_sym()
16 @SYM ||= {}
17 end
18
19 def [](name)
20 return @SYM[name.to_s][0]
21 end
22
23 def dlload(*libnames)
24 if( !defined?(@LIBS) )
25 @LIBS = []
26 end
27 libnames.each{|libname|
28 if( !LIB_MAP[libname] )
29 LIB_MAP[libname] = DL.dlopen(libname)
30 end
31 @LIBS.push(LIB_MAP[libname])
32 }
33 end
34 alias dllink :dlload
35
36 def parse_cproto(proto)
37 proto = proto.gsub(/\s+/, " ").strip
38 case proto
39 when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
40 ret = $1
41 args = $2.strip()
42 ret = ret.split(/\s+/)
43 args = args.split(/\s*,\s*/)
44 func = ret.pop()
45 if( func =~ /^\*/ )
46 func.gsub!(/^\*+/,"")
47 ret.push("*")
48 end
49 ret = ret.join(" ")
50 return [func, ret, args]
51 else
52 raise(RuntimeError,"can't parse the function prototype: #{proto}")
53 end
54 end
55
56 # example:
57 # extern "int strlen(char*)"
58 #
59 def extern(proto)
60 func,ret,args = parse_cproto(proto)
61 return import(func, ret, args)
62 end
63
64 # example:
65 # callback "int method_name(int, char*)"
66 #
67 def callback(proto)
68 func,ret,args = parse_cproto(proto)
69
70 init_types()
71 init_sym()
72
73 rty,renc,rdec = @types.encode_return_type(ret)
74 if( !rty )
75 raise(TypeError, "unsupported type: #{ret}")
76 end
77 ty,enc,dec = encode_argument_types(args)
78 symty = rty + ty
79
80 module_eval("module_function :#{func}")
81 sym = module_eval([
82 "DL::callback(\"#{symty}\"){|*args|",
83 " sym,rdec,enc,dec = @SYM['#{func}']",
84 " args = enc.call(args) if enc",
85 " r,rs = #{func}(*args)",
86 " r = renc.call(r) if rdec",
87 " rs = dec.call(rs) if (dec && rs)",
88 " @retval = r",
89 " @args = rs",
90 " r",
91 "}",
92 ].join("\n"))
93
94 @SYM[func] = [sym,rdec,enc,dec]
95
96 return sym
97 end
98
99 # example:
100 # typealias("uint", "unsigned int")
101 #
102 def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil)
103 init_types()
104 @types.typealias(alias_type, ty1, enc1, dec1,
105 ty2||ty1, enc2, dec2)
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_return_type(rettype)
139 if( !rty )
140 raise(TypeError, "unsupported type: #{rettype}")
141 end
142 ty,enc,dec = encode_argument_types(argtypes)
143 symty = rty + ty
144
145 sym = symbol(name, symty)
146
147 mname = name.dup
148 if( ?A <= mname[0] && mname[0] <= ?Z )
149 mname[0,1] = mname[0,1].downcase
150 end
151 @SYM[mname] = [sym,rdec,enc,dec]
152
153 module_eval [
154 "def #{mname}(*args)",
155 " sym,rdec,enc,dec = @SYM['#{mname}']",
156 " args = enc.call(args) if enc",
157 if( $DEBUG )
158 " p \"[DL] call #{mname} with \#{args.inspect}\""
159 else
160 ""
161 end,
162 " r,rs = sym.call(*args)",
163 if( $DEBUG )
164 " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\""
165 else
166 ""
167 end,
168 " r = rdec.call(r) if rdec",
169 " rs = dec.call(rs) if dec",
170 " @retval = r",
171 " @args = rs",
172 " return r",
173 "end",
174 "module_function :#{mname}",
175 ].join("\n")
176
177 return sym
178 end
179
180 def _args_
181 return @args
182 end
183
184 def _retval_
185 return @retval
186 end
187
188 def encode_argument_types(tys)
189 init_types()
190 encty = []
191 enc = nil
192 dec = nil
193 tys.each_with_index{|ty,idx|
194 ty,c1,c2 = @types.encode_argument_type(ty)
195 if( !ty )
196 raise(TypeError, "unsupported type: #{ty}")
197 end
198 encty.push(ty)
199 if( enc )
200 if( c1 )
201 conv1 = enc
202 enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v}
203 end
204 else
205 if( c1 )
206 enc = proc{|v| v[idx] = c1.call(v[idx]); v}
207 end
208 end
209 if( dec )
210 if( c2 )
211 conv2 = dec
212 dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v}
213 end
214 else
215 if( c2 )
216 dec = proc{|v| v[idx] = c2.call(v[idx]); v}
217 end
218 end
219 }
220 return [encty.join, enc, dec]
221 end
222 end # end of Internal
223 include Internal
224 end # end of Importable
225end
Note: See TracBrowser for help on using the repository browser.