diff options
author | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-08-22 01:53:51 +0000 |
---|---|---|
committer | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2007-08-22 01:53:51 +0000 |
commit | 1e760c0be3ed35874204114e7454509f740c0fe2 (patch) | |
tree | a75eb2b1eea073830902d1fa49c568c4525c8b57 /ruby_1_8_6/ext/dl/lib | |
parent | a2055d63b41a6678dc7aeb17d0bece314e700c5a (diff) |
add tag v1_8_6_71v1_8_5_71
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_5_71@13189 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ruby_1_8_6/ext/dl/lib')
-rw-r--r-- | ruby_1_8_6/ext/dl/lib/dl/import.rb | 225 | ||||
-rw-r--r-- | ruby_1_8_6/ext/dl/lib/dl/struct.rb | 149 | ||||
-rw-r--r-- | ruby_1_8_6/ext/dl/lib/dl/types.rb | 245 | ||||
-rw-r--r-- | ruby_1_8_6/ext/dl/lib/dl/win32.rb | 25 |
4 files changed, 644 insertions, 0 deletions
diff --git a/ruby_1_8_6/ext/dl/lib/dl/import.rb b/ruby_1_8_6/ext/dl/lib/dl/import.rb new file mode 100644 index 0000000000..01ee2490e8 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/import.rb @@ -0,0 +1,225 @@ +# -*- ruby -*- + +require 'dl' +require 'dl/types' + +module DL + module Importable + LIB_MAP = {} + + module Internal + def init_types() + @types ||= ::DL::Types.new + end + + def init_sym() + @SYM ||= {} + end + + def [](name) + return @SYM[name.to_s][0] + end + + def dlload(*libnames) + if( !defined?(@LIBS) ) + @LIBS = [] + end + libnames.each{|libname| + if( !LIB_MAP[libname] ) + LIB_MAP[libname] = DL.dlopen(libname) + end + @LIBS.push(LIB_MAP[libname]) + } + end + alias dllink :dlload + + def parse_cproto(proto) + proto = proto.gsub(/\s+/, " ").strip + case proto + when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/ + ret = $1 + args = $2.strip() + ret = ret.split(/\s+/) + args = args.split(/\s*,\s*/) + func = ret.pop() + if( func =~ /^\*/ ) + func.gsub!(/^\*+/,"") + ret.push("*") + end + ret = ret.join(" ") + return [func, ret, args] + else + raise(RuntimeError,"can't parse the function prototype: #{proto}") + end + end + + # example: + # extern "int strlen(char*)" + # + def extern(proto) + func,ret,args = parse_cproto(proto) + return import(func, ret, args) + end + + # example: + # callback "int method_name(int, char*)" + # + def callback(proto) + func,ret,args = parse_cproto(proto) + + init_types() + init_sym() + + rty,renc,rdec = @types.encode_return_type(ret) + if( !rty ) + raise(TypeError, "unsupported type: #{ret}") + end + ty,enc,dec = encode_argument_types(args) + symty = rty + ty + + module_eval("module_function :#{func}") + sym = module_eval([ + "DL::callback(\"#{symty}\"){|*args|", + " sym,rdec,enc,dec = @SYM['#{func}']", + " args = enc.call(args) if enc", + " r,rs = #{func}(*args)", + " r = renc.call(r) if rdec", + " rs = dec.call(rs) if (dec && rs)", + " @retval = r", + " @args = rs", + " r", + "}", + ].join("\n")) + + @SYM[func] = [sym,rdec,enc,dec] + + return sym + end + + # example: + # typealias("uint", "unsigned int") + # + def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil) + init_types() + @types.typealias(alias_type, ty1, enc1, dec1, + ty2||ty1, enc2, dec2) + end + + # example: + # symbol "foo_value" + # symbol "foo_func", "IIP" + # + def symbol(name, ty = nil) + sym = nil + @LIBS.each{|lib| + begin + if( ty ) + sym = lib[name, ty] + else + sym = lib[name] + end + rescue + next + end + } + if( !sym ) + raise(RuntimeError, "can't find the symbol `#{name}'") + end + return sym + end + + # example: + # import("get_length", "int", ["void*", "int"]) + # + def import(name, rettype, argtypes = nil) + init_types() + init_sym() + + rty,_,rdec = @types.encode_return_type(rettype) + if( !rty ) + raise(TypeError, "unsupported type: #{rettype}") + end + ty,enc,dec = encode_argument_types(argtypes) + symty = rty + ty + + sym = symbol(name, symty) + + mname = name.dup + if( ?A <= mname[0] && mname[0] <= ?Z ) + mname[0,1] = mname[0,1].downcase + end + @SYM[mname] = [sym,rdec,enc,dec] + + module_eval [ + "def #{mname}(*args)", + " sym,rdec,enc,dec = @SYM['#{mname}']", + " args = enc.call(args) if enc", + if( $DEBUG ) + " p \"[DL] call #{mname} with \#{args.inspect}\"" + else + "" + end, + " r,rs = sym.call(*args)", + if( $DEBUG ) + " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\"" + else + "" + end, + " r = rdec.call(r) if rdec", + " rs = dec.call(rs) if dec", + " @retval = r", + " @args = rs", + " return r", + "end", + "module_function :#{mname}", + ].join("\n") + + return sym + end + + def _args_ + return @args + end + + def _retval_ + return @retval + end + + def encode_argument_types(tys) + init_types() + encty = [] + enc = nil + dec = nil + tys.each_with_index{|ty,idx| + ty,c1,c2 = @types.encode_argument_type(ty) + if( !ty ) + raise(TypeError, "unsupported type: #{ty}") + end + encty.push(ty) + if( enc ) + if( c1 ) + conv1 = enc + enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v} + end + else + if( c1 ) + enc = proc{|v| v[idx] = c1.call(v[idx]); v} + end + end + if( dec ) + if( c2 ) + conv2 = dec + dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v} + end + else + if( c2 ) + dec = proc{|v| v[idx] = c2.call(v[idx]); v} + end + end + } + return [encty.join, enc, dec] + end + end # end of Internal + include Internal + end # end of Importable +end diff --git a/ruby_1_8_6/ext/dl/lib/dl/struct.rb b/ruby_1_8_6/ext/dl/lib/dl/struct.rb new file mode 100644 index 0000000000..33f303fe22 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/struct.rb @@ -0,0 +1,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 diff --git a/ruby_1_8_6/ext/dl/lib/dl/types.rb b/ruby_1_8_6/ext/dl/lib/dl/types.rb new file mode 100644 index 0000000000..1144917dae --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/types.rb @@ -0,0 +1,245 @@ +# -*- ruby -*- + +require 'dl' + +module DL + class Types + TYPES = [ + # FORMAT: + # ["alias name", + # "type name", encoding_method, decoding_method, for function prototypes + # "type name", encoding_method, decoding_method] for structures (not implemented) + + # for Windows + ["DWORD", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["PDWORD", "unsigned long *", nil, nil, + "unsigned long *", nil, nil], + ["WORD", "unsigned short", nil, nil, + "unsigned short", nil, nil], + ["PWORD", "unsigned int *", nil, nil, + "unsigned int *", nil, nil], + ["BYTE", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["PBYTE", "unsigned char *", nil, nil, + "unsigned char *", nil, nil], + ["BOOL", "ibool", nil, nil, + "ibool", nil, nil], + ["ATOM", "int", nil, nil, + "int", nil, nil], + ["BYTE", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["PBYTE", "unsigned char *", nil, nil, + "unsigned char *", nil, nil], + ["UINT", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["ULONG", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["UCHAR", "unsigned char", nil, nil, + "unsigned char", nil, nil], + ["HANDLE", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["PHANDLE","void*", nil, nil, + "void*", nil, nil], + ["PVOID", "void*", nil, nil, + "void*", nil, nil], + ["LPCSTR", "char*", nil, nil, + "char*", nil, nil], + ["HDC", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["HWND", "unsigned int", nil, nil, + "unsigned int", nil, nil], + + # Others + ["uint", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["u_int", "unsigned int", nil, nil, + "unsigned int", nil, nil], + ["ulong", "unsigned long", nil, nil, + "unsigned long", nil, nil], + ["u_long", "unsigned long", nil, nil, + "unsigned long", nil, nil], + + # DL::Importable primitive types + ["ibool", + "I", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "I", + proc{|v| v ? 1 : 0 }, + proc{|v| (v != 0) ? true : false} ], + ["cbool", + "C", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "C", + proc{|v,len| v ? 1 : 0}, + proc{|v,len| (v != 0) ? true : false}], + ["lbool", + "L", + proc{|v| v ? 1 : 0}, + proc{|v| (v != 0) ? true : false}, + "L", + proc{|v,len| v ? 1 : 0}, + proc{|v,len| (v != 0) ? true : false}], + ["unsigned char", + "C", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}, + "C", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}], + ["unsigned short", + "H", + proc{|v| [v].pack("S").unpack("s")[0]}, + proc{|v| [v].pack("s").unpack("S")[0]}, + "H", + proc{|v| [v].pack("S").unpack("s")[0]}, + proc{|v| [v].pack("s").unpack("S")[0]}], + ["unsigned int", + "I", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}, + "I", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}], + ["unsigned long", + "L", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}, + "L", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}], + ["unsigned char ref", + "c", + proc{|v| [v].pack("C").unpack("c")[0]}, + proc{|v| [v].pack("c").unpack("C")[0]}, + nil, nil, nil], + ["unsigned int ref", + "i", + proc{|v| [v].pack("I").unpack("i")[0]}, + proc{|v| [v].pack("i").unpack("I")[0]}, + nil, nil, nil], + ["unsigned long ref", + "l", + proc{|v| [v].pack("L").unpack("l")[0]}, + proc{|v| [v].pack("l").unpack("L")[0]}, + nil, nil, nil], + ["char ref", "c", nil, nil, + nil, nil, nil], + ["short ref", "h", nil, nil, + nil, nil, nil], + ["int ref", "i", nil, nil, + nil, nil, nil], + ["long ref", "l", nil, nil, + nil, nil, nil], + ["float ref", "f", nil, nil, + nil, nil, nil], + ["double ref","d", nil, nil, + nil, nil, nil], + ["char", "C", nil, nil, + "C", nil, nil], + ["short", "H", nil, nil, + "H", nil, nil], + ["int", "I", nil, nil, + "I", nil, nil], + ["long", "L", nil, nil, + "L", nil, nil], + ["float", "F", nil, nil, + "F", nil, nil], + ["double", "D", nil, nil, + "D", nil, nil], + [/^char\s*\*$/,"s",nil, nil, + "S",nil, nil], + [/^const char\s*\*$/,"S",nil, nil, + "S",nil, nil], + [/^.+\*$/, "P", nil, nil, + "P", nil, nil], + [/^.+\[\]$/, "a", nil, nil, + "a", nil, nil], + ["void", "0", nil, nil, + nil, nil, nil], + ] + + def initialize + init_types() + end + + def typealias(ty1, ty2, enc=nil, dec=nil, ty3=nil, senc=nil, sdec=nil) + @TYDEFS.unshift([ty1, ty2, enc, dec, ty3, senc, sdec]) + end + + def init_types + @TYDEFS = TYPES.dup + end + + def encode_argument_type(alias_type) + proc_encode = nil + proc_decode = nil + @TYDEFS.each{|aty,ty,enc,dec,_,_,_| + if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) + alias_type = alias_type.gsub(aty,ty) if ty + alias_type.strip! if alias_type + if( proc_encode ) + if( enc ) + conv1 = proc_encode + proc_encode = proc{|v| enc.call(conv1.call(v))} + end + else + if( enc ) + proc_encode = enc + end + end + if( proc_decode ) + if( dec ) + conv2 = proc_decode + proc_decode = proc{|v| dec.call(conv2.call(v))} + end + else + if( dec ) + proc_decode = dec + end + end + end + } + return [alias_type, proc_encode, proc_decode] + end + + def encode_return_type(ty) + ty, enc, dec = encode_argument_type(ty) + return [ty, enc, dec] + end + + def encode_struct_type(alias_type) + proc_encode = nil + proc_decode = nil + @TYDEFS.each{|aty,_,_,_,ty,enc,dec| + if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) ) + alias_type = alias_type.gsub(aty,ty) if ty + alias_type.strip! if alias_type + if( proc_encode ) + if( enc ) + conv1 = proc_encode + proc_encode = proc{|v| enc.call(conv1.call(v))} + end + else + if( enc ) + proc_encode = enc + end + end + if( proc_decode ) + if( dec ) + conv2 = proc_decode + proc_decode = proc{|v| dec.call(conv2.call(v))} + end + else + if( dec ) + proc_decode = dec + end + end + end + } + return [alias_type, proc_encode, proc_decode] + end + end # end of Types +end diff --git a/ruby_1_8_6/ext/dl/lib/dl/win32.rb b/ruby_1_8_6/ext/dl/lib/dl/win32.rb new file mode 100644 index 0000000000..0fed47c324 --- /dev/null +++ b/ruby_1_8_6/ext/dl/lib/dl/win32.rb @@ -0,0 +1,25 @@ +# -*- ruby -*- + +require 'dl' + +class Win32API + DLL = {} + + def initialize(dllname, func, import, export = "0") + prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1') + handle = DLL[dllname] ||= DL::Handle.new(dllname) + @sym = handle.sym(func, prototype) + end + + def call(*args) + import = @sym.proto.split("", 2)[1] + args.each_with_index do |x, i| + args[i] = nil if x == 0 and import[i] == ?S + args[i], = [x].pack("I").unpack("i") if import[i] == ?I + end + ret, = @sym.call(*args) + return ret || 0 + end + + alias Call call +end |