fiddle 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +13 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/fiddle/closure.c +345 -0
- data/ext/fiddle/closure.h +8 -0
- data/ext/fiddle/conversions.c +141 -0
- data/ext/fiddle/conversions.h +44 -0
- data/ext/fiddle/extconf.rb +183 -0
- data/ext/fiddle/extlibs +2 -0
- data/ext/fiddle/fiddle.c +454 -0
- data/ext/fiddle/fiddle.h +138 -0
- data/ext/fiddle/function.c +315 -0
- data/ext/fiddle/function.h +8 -0
- data/ext/fiddle/handle.c +479 -0
- data/ext/fiddle/pointer.c +721 -0
- data/ext/fiddle/win32/fficonfig.h +29 -0
- data/ext/fiddle/win32/libffi-3.2.1-mswin.patch +191 -0
- data/ext/fiddle/win32/libffi-config.rb +48 -0
- data/ext/fiddle/win32/libffi.mk.tmpl +96 -0
- data/fiddle.gemspec +23 -0
- data/lib/fiddle.rb +56 -0
- data/lib/fiddle/closure.rb +49 -0
- data/lib/fiddle/cparser.rb +194 -0
- data/lib/fiddle/function.rb +18 -0
- data/lib/fiddle/import.rb +318 -0
- data/lib/fiddle/pack.rb +129 -0
- data/lib/fiddle/struct.rb +244 -0
- data/lib/fiddle/types.rb +72 -0
- data/lib/fiddle/value.rb +113 -0
- metadata +136 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
module Fiddle
|
3
|
+
class Closure
|
4
|
+
|
5
|
+
# the C type of the return of the FFI closure
|
6
|
+
attr_reader :ctype
|
7
|
+
|
8
|
+
# arguments of the FFI closure
|
9
|
+
attr_reader :args
|
10
|
+
|
11
|
+
# Extends Fiddle::Closure to allow for building the closure in a block
|
12
|
+
class BlockCaller < Fiddle::Closure
|
13
|
+
|
14
|
+
# == Description
|
15
|
+
#
|
16
|
+
# Construct a new BlockCaller object.
|
17
|
+
#
|
18
|
+
# * +ctype+ is the C type to be returned
|
19
|
+
# * +args+ are passed the callback
|
20
|
+
# * +abi+ is the abi of the closure
|
21
|
+
#
|
22
|
+
# If there is an error in preparing the +ffi_cif+ or +ffi_prep_closure+,
|
23
|
+
# then a RuntimeError will be raised.
|
24
|
+
#
|
25
|
+
# == Example
|
26
|
+
#
|
27
|
+
# include Fiddle
|
28
|
+
#
|
29
|
+
# cb = Closure::BlockCaller.new(TYPE_INT, [TYPE_INT]) do |one|
|
30
|
+
# one
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# func = Function.new(cb, [TYPE_INT], TYPE_INT)
|
34
|
+
#
|
35
|
+
def initialize ctype, args, abi = Fiddle::Function::DEFAULT, &block
|
36
|
+
super(ctype, args, abi)
|
37
|
+
@block = block
|
38
|
+
end
|
39
|
+
|
40
|
+
# Calls the constructed BlockCaller, with +args+
|
41
|
+
#
|
42
|
+
# For an example see Fiddle::Closure::BlockCaller.new
|
43
|
+
#
|
44
|
+
def call *args
|
45
|
+
@block.call(*args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
module Fiddle
|
3
|
+
# A mixin that provides methods for parsing C struct and prototype signatures.
|
4
|
+
#
|
5
|
+
# == Example
|
6
|
+
# require 'fiddle/import'
|
7
|
+
#
|
8
|
+
# include Fiddle::CParser
|
9
|
+
# #=> Object
|
10
|
+
#
|
11
|
+
# parse_ctype('int')
|
12
|
+
# #=> Fiddle::TYPE_INT
|
13
|
+
#
|
14
|
+
# parse_struct_signature(['int i', 'char c'])
|
15
|
+
# #=> [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]]
|
16
|
+
#
|
17
|
+
# parse_signature('double sum(double, double)')
|
18
|
+
# #=> ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]]
|
19
|
+
#
|
20
|
+
module CParser
|
21
|
+
# Parses a C struct's members
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
#
|
25
|
+
# include Fiddle::CParser
|
26
|
+
# #=> Object
|
27
|
+
#
|
28
|
+
# parse_struct_signature(['int i', 'char c'])
|
29
|
+
# #=> [[Fiddle::TYPE_INT, Fiddle::TYPE_CHAR], ["i", "c"]]
|
30
|
+
#
|
31
|
+
# parse_struct_signature(['char buffer[80]'])
|
32
|
+
# #=> [[[Fiddle::TYPE_CHAR, 80]], ["buffer"]]
|
33
|
+
#
|
34
|
+
def parse_struct_signature(signature, tymap=nil)
|
35
|
+
if signature.is_a?(String)
|
36
|
+
signature = split_arguments(signature, /[,;]/)
|
37
|
+
end
|
38
|
+
mems = []
|
39
|
+
tys = []
|
40
|
+
signature.each{|msig|
|
41
|
+
msig = compact(msig)
|
42
|
+
case msig
|
43
|
+
when /^[\w\*\s]+[\*\s](\w+)$/
|
44
|
+
mems.push($1)
|
45
|
+
tys.push(parse_ctype(msig, tymap))
|
46
|
+
when /^[\w\*\s]+\(\*(\w+)\)\(.*?\)$/
|
47
|
+
mems.push($1)
|
48
|
+
tys.push(parse_ctype(msig, tymap))
|
49
|
+
when /^([\w\*\s]+[\*\s])(\w+)\[(\d+)\]$/
|
50
|
+
mems.push($2)
|
51
|
+
tys.push([parse_ctype($1.strip, tymap), $3.to_i])
|
52
|
+
when /^([\w\*\s]+)\[(\d+)\](\w+)$/
|
53
|
+
mems.push($3)
|
54
|
+
tys.push([parse_ctype($1.strip, tymap), $2.to_i])
|
55
|
+
else
|
56
|
+
raise(RuntimeError,"can't parse the struct member: #{msig}")
|
57
|
+
end
|
58
|
+
}
|
59
|
+
return tys, mems
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parses a C prototype signature
|
63
|
+
#
|
64
|
+
# If Hash +tymap+ is provided, the return value and the arguments from the
|
65
|
+
# +signature+ are expected to be keys, and the value will be the C type to
|
66
|
+
# be looked up.
|
67
|
+
#
|
68
|
+
# Example:
|
69
|
+
#
|
70
|
+
# include Fiddle::CParser
|
71
|
+
# #=> Object
|
72
|
+
#
|
73
|
+
# parse_signature('double sum(double, double)')
|
74
|
+
# #=> ["sum", Fiddle::TYPE_DOUBLE, [Fiddle::TYPE_DOUBLE, Fiddle::TYPE_DOUBLE]]
|
75
|
+
#
|
76
|
+
# parse_signature('void update(void (*cb)(int code))')
|
77
|
+
# #=> ["update", Fiddle::TYPE_VOID, [Fiddle::TYPE_VOIDP]]
|
78
|
+
#
|
79
|
+
# parse_signature('char (*getbuffer(void))[80]')
|
80
|
+
# #=> ["getbuffer", Fiddle::TYPE_VOIDP, []]
|
81
|
+
#
|
82
|
+
def parse_signature(signature, tymap=nil)
|
83
|
+
tymap ||= {}
|
84
|
+
case compact(signature)
|
85
|
+
when /^(?:[\w\*\s]+)\(\*(\w+)\((.*?)\)\)(?:\[\w*\]|\(.*?\));?$/
|
86
|
+
func, args = $1, $2
|
87
|
+
return [func, TYPE_VOIDP, split_arguments(args).collect {|arg| parse_ctype(arg, tymap)}]
|
88
|
+
when /^([\w\*\s]+[\*\s])(\w+)\((.*?)\);?$/
|
89
|
+
ret, func, args = $1.strip, $2, $3
|
90
|
+
return [func, parse_ctype(ret, tymap), split_arguments(args).collect {|arg| parse_ctype(arg, tymap)}]
|
91
|
+
else
|
92
|
+
raise(RuntimeError,"can't parse the function prototype: #{signature}")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Given a String of C type +ty+, returns the corresponding Fiddle constant.
|
97
|
+
#
|
98
|
+
# +ty+ can also accept an Array of C type Strings, and will be returned in
|
99
|
+
# a corresponding Array.
|
100
|
+
#
|
101
|
+
# If Hash +tymap+ is provided, +ty+ is expected to be the key, and the
|
102
|
+
# value will be the C type to be looked up.
|
103
|
+
#
|
104
|
+
# Example:
|
105
|
+
#
|
106
|
+
# include Fiddle::CParser
|
107
|
+
# #=> Object
|
108
|
+
#
|
109
|
+
# parse_ctype('int')
|
110
|
+
# #=> Fiddle::TYPE_INT
|
111
|
+
#
|
112
|
+
# parse_ctype('double diff')
|
113
|
+
# #=> Fiddle::TYPE_DOUBLE
|
114
|
+
#
|
115
|
+
# parse_ctype('unsigned char byte')
|
116
|
+
# #=> -Fiddle::TYPE_CHAR
|
117
|
+
#
|
118
|
+
# parse_ctype('const char* const argv[]')
|
119
|
+
# #=> -Fiddle::TYPE_VOIDP
|
120
|
+
#
|
121
|
+
def parse_ctype(ty, tymap=nil)
|
122
|
+
tymap ||= {}
|
123
|
+
case ty
|
124
|
+
when Array
|
125
|
+
return [parse_ctype(ty[0], tymap), ty[1]]
|
126
|
+
when 'void'
|
127
|
+
return TYPE_VOID
|
128
|
+
when /^(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?$/
|
129
|
+
if( defined?(TYPE_LONG_LONG) )
|
130
|
+
return TYPE_LONG_LONG
|
131
|
+
else
|
132
|
+
raise(RuntimeError, "unsupported type: #{ty}")
|
133
|
+
end
|
134
|
+
when /^(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?$/
|
135
|
+
if( defined?(TYPE_LONG_LONG) )
|
136
|
+
return -TYPE_LONG_LONG
|
137
|
+
else
|
138
|
+
raise(RuntimeError, "unsupported type: #{ty}")
|
139
|
+
end
|
140
|
+
when /^(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?$/
|
141
|
+
return TYPE_LONG
|
142
|
+
when /^unsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?$/
|
143
|
+
return -TYPE_LONG
|
144
|
+
when /^(?:signed\s+)?int(?:\s+\w+)?$/
|
145
|
+
return TYPE_INT
|
146
|
+
when /^(?:unsigned\s+int|uint)(?:\s+\w+)?$/
|
147
|
+
return -TYPE_INT
|
148
|
+
when /^(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?$/
|
149
|
+
return TYPE_SHORT
|
150
|
+
when /^unsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?$/
|
151
|
+
return -TYPE_SHORT
|
152
|
+
when /^(?:signed\s+)?char(?:\s+\w+)?$/
|
153
|
+
return TYPE_CHAR
|
154
|
+
when /^unsigned\s+char(?:\s+\w+)?$/
|
155
|
+
return -TYPE_CHAR
|
156
|
+
when /^float(?:\s+\w+)?$/
|
157
|
+
return TYPE_FLOAT
|
158
|
+
when /^double(?:\s+\w+)?$/
|
159
|
+
return TYPE_DOUBLE
|
160
|
+
when /^size_t(?:\s+\w+)?$/
|
161
|
+
return TYPE_SIZE_T
|
162
|
+
when /^ssize_t(?:\s+\w+)?$/
|
163
|
+
return TYPE_SSIZE_T
|
164
|
+
when /^ptrdiff_t(?:\s+\w+)?$/
|
165
|
+
return TYPE_PTRDIFF_T
|
166
|
+
when /^intptr_t(?:\s+\w+)?$/
|
167
|
+
return TYPE_INTPTR_T
|
168
|
+
when /^uintptr_t(?:\s+\w+)?$/
|
169
|
+
return TYPE_UINTPTR_T
|
170
|
+
when /\*/, /\[[\s\d]*\]/
|
171
|
+
return TYPE_VOIDP
|
172
|
+
else
|
173
|
+
ty = ty.split(' ', 2)[0]
|
174
|
+
if( tymap[ty] )
|
175
|
+
return parse_ctype(tymap[ty], tymap)
|
176
|
+
else
|
177
|
+
raise(DLError, "unknown type: #{ty}")
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def split_arguments(arguments, sep=',')
|
185
|
+
return [] if arguments.strip == 'void'
|
186
|
+
arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+)(?:#{sep}\s*|$)/).collect {|m| m[0]}
|
187
|
+
end
|
188
|
+
|
189
|
+
def compact(signature)
|
190
|
+
signature.gsub(/\s+/, ' ').gsub(/\s*([\(\)\[\]\*,;])\s*/, '\1').strip
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
module Fiddle
|
3
|
+
class Function
|
4
|
+
# The ABI of the Function.
|
5
|
+
attr_reader :abi
|
6
|
+
|
7
|
+
# The address of this function
|
8
|
+
attr_reader :ptr
|
9
|
+
|
10
|
+
# The name of this function
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
# The integer memory location of this function
|
14
|
+
def to_i
|
15
|
+
ptr.to_i
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,318 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'fiddle'
|
3
|
+
require 'fiddle/struct'
|
4
|
+
require 'fiddle/cparser'
|
5
|
+
|
6
|
+
module Fiddle
|
7
|
+
|
8
|
+
# Used internally by Fiddle::Importer
|
9
|
+
class CompositeHandler
|
10
|
+
# Create a new handler with the open +handlers+
|
11
|
+
#
|
12
|
+
# Used internally by Fiddle::Importer.dlload
|
13
|
+
def initialize(handlers)
|
14
|
+
@handlers = handlers
|
15
|
+
end
|
16
|
+
|
17
|
+
# Array of the currently loaded libraries.
|
18
|
+
def handlers()
|
19
|
+
@handlers
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the address as an Integer from any handlers with the function
|
23
|
+
# named +symbol+.
|
24
|
+
#
|
25
|
+
# Raises a DLError if the handle is closed.
|
26
|
+
def sym(symbol)
|
27
|
+
@handlers.each{|handle|
|
28
|
+
if( handle )
|
29
|
+
begin
|
30
|
+
addr = handle.sym(symbol)
|
31
|
+
return addr
|
32
|
+
rescue DLError
|
33
|
+
end
|
34
|
+
end
|
35
|
+
}
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# See Fiddle::CompositeHandler.sym
|
40
|
+
def [](symbol)
|
41
|
+
sym(symbol)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# A DSL that provides the means to dynamically load libraries and build
|
46
|
+
# modules around them including calling extern functions within the C
|
47
|
+
# library that has been loaded.
|
48
|
+
#
|
49
|
+
# == Example
|
50
|
+
#
|
51
|
+
# require 'fiddle'
|
52
|
+
# require 'fiddle/import'
|
53
|
+
#
|
54
|
+
# module LibSum
|
55
|
+
# extend Fiddle::Importer
|
56
|
+
# dlload './libsum.so'
|
57
|
+
# extern 'double sum(double*, int)'
|
58
|
+
# extern 'double split(double)'
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
module Importer
|
62
|
+
include Fiddle
|
63
|
+
include CParser
|
64
|
+
extend Importer
|
65
|
+
|
66
|
+
attr_reader :type_alias
|
67
|
+
private :type_alias
|
68
|
+
|
69
|
+
# Creates an array of handlers for the given +libs+, can be an instance of
|
70
|
+
# Fiddle::Handle, Fiddle::Importer, or will create a new instance of
|
71
|
+
# Fiddle::Handle using Fiddle.dlopen
|
72
|
+
#
|
73
|
+
# Raises a DLError if the library cannot be loaded.
|
74
|
+
#
|
75
|
+
# See Fiddle.dlopen
|
76
|
+
def dlload(*libs)
|
77
|
+
handles = libs.collect{|lib|
|
78
|
+
case lib
|
79
|
+
when nil
|
80
|
+
nil
|
81
|
+
when Handle
|
82
|
+
lib
|
83
|
+
when Importer
|
84
|
+
lib.handlers
|
85
|
+
else
|
86
|
+
begin
|
87
|
+
Fiddle.dlopen(lib)
|
88
|
+
rescue DLError
|
89
|
+
raise(DLError, "can't load #{lib}")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
}.flatten()
|
93
|
+
@handler = CompositeHandler.new(handles)
|
94
|
+
@func_map = {}
|
95
|
+
@type_alias = {}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Sets the type alias for +alias_type+ as +orig_type+
|
99
|
+
def typealias(alias_type, orig_type)
|
100
|
+
@type_alias[alias_type] = orig_type
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns the sizeof +ty+, using Fiddle::Importer.parse_ctype to determine
|
104
|
+
# the C type and the appropriate Fiddle constant.
|
105
|
+
def sizeof(ty)
|
106
|
+
case ty
|
107
|
+
when String
|
108
|
+
ty = parse_ctype(ty, type_alias).abs()
|
109
|
+
case ty
|
110
|
+
when TYPE_CHAR
|
111
|
+
return SIZEOF_CHAR
|
112
|
+
when TYPE_SHORT
|
113
|
+
return SIZEOF_SHORT
|
114
|
+
when TYPE_INT
|
115
|
+
return SIZEOF_INT
|
116
|
+
when TYPE_LONG
|
117
|
+
return SIZEOF_LONG
|
118
|
+
when TYPE_LONG_LONG
|
119
|
+
return SIZEOF_LONG_LONG
|
120
|
+
when TYPE_FLOAT
|
121
|
+
return SIZEOF_FLOAT
|
122
|
+
when TYPE_DOUBLE
|
123
|
+
return SIZEOF_DOUBLE
|
124
|
+
when TYPE_VOIDP
|
125
|
+
return SIZEOF_VOIDP
|
126
|
+
else
|
127
|
+
raise(DLError, "unknown type: #{ty}")
|
128
|
+
end
|
129
|
+
when Class
|
130
|
+
if( ty.instance_methods().include?(:to_ptr) )
|
131
|
+
return ty.size()
|
132
|
+
end
|
133
|
+
end
|
134
|
+
return Pointer[ty].size()
|
135
|
+
end
|
136
|
+
|
137
|
+
def parse_bind_options(opts)
|
138
|
+
h = {}
|
139
|
+
while( opt = opts.shift() )
|
140
|
+
case opt
|
141
|
+
when :stdcall, :cdecl
|
142
|
+
h[:call_type] = opt
|
143
|
+
when :carried, :temp, :temporal, :bind
|
144
|
+
h[:callback_type] = opt
|
145
|
+
h[:carrier] = opts.shift()
|
146
|
+
else
|
147
|
+
h[opt] = true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
h
|
151
|
+
end
|
152
|
+
private :parse_bind_options
|
153
|
+
|
154
|
+
# :stopdoc:
|
155
|
+
CALL_TYPE_TO_ABI = Hash.new { |h, k|
|
156
|
+
raise RuntimeError, "unsupported call type: #{k}"
|
157
|
+
}.merge({ :stdcall => (Function::STDCALL rescue Function::DEFAULT),
|
158
|
+
:cdecl => Function::DEFAULT,
|
159
|
+
nil => Function::DEFAULT
|
160
|
+
}).freeze
|
161
|
+
private_constant :CALL_TYPE_TO_ABI
|
162
|
+
# :startdoc:
|
163
|
+
|
164
|
+
# Creates a global method from the given C +signature+.
|
165
|
+
def extern(signature, *opts)
|
166
|
+
symname, ctype, argtype = parse_signature(signature, type_alias)
|
167
|
+
opt = parse_bind_options(opts)
|
168
|
+
f = import_function(symname, ctype, argtype, opt[:call_type])
|
169
|
+
name = symname.gsub(/@.+/,'')
|
170
|
+
@func_map[name] = f
|
171
|
+
# define_method(name){|*args,&block| f.call(*args,&block)}
|
172
|
+
begin
|
173
|
+
/^(.+?):(\d+)/ =~ caller.first
|
174
|
+
file, line = $1, $2.to_i
|
175
|
+
rescue
|
176
|
+
file, line = __FILE__, __LINE__+3
|
177
|
+
end
|
178
|
+
module_eval(<<-EOS, file, line)
|
179
|
+
def #{name}(*args, &block)
|
180
|
+
@func_map['#{name}'].call(*args,&block)
|
181
|
+
end
|
182
|
+
EOS
|
183
|
+
module_function(name)
|
184
|
+
f
|
185
|
+
end
|
186
|
+
|
187
|
+
# Creates a global method from the given C +signature+ using the given
|
188
|
+
# +opts+ as bind parameters with the given block.
|
189
|
+
def bind(signature, *opts, &blk)
|
190
|
+
name, ctype, argtype = parse_signature(signature, type_alias)
|
191
|
+
h = parse_bind_options(opts)
|
192
|
+
case h[:callback_type]
|
193
|
+
when :bind, nil
|
194
|
+
f = bind_function(name, ctype, argtype, h[:call_type], &blk)
|
195
|
+
else
|
196
|
+
raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
|
197
|
+
end
|
198
|
+
@func_map[name] = f
|
199
|
+
#define_method(name){|*args,&block| f.call(*args,&block)}
|
200
|
+
begin
|
201
|
+
/^(.+?):(\d+)/ =~ caller.first
|
202
|
+
file, line = $1, $2.to_i
|
203
|
+
rescue
|
204
|
+
file, line = __FILE__, __LINE__+3
|
205
|
+
end
|
206
|
+
module_eval(<<-EOS, file, line)
|
207
|
+
def #{name}(*args,&block)
|
208
|
+
@func_map['#{name}'].call(*args,&block)
|
209
|
+
end
|
210
|
+
EOS
|
211
|
+
module_function(name)
|
212
|
+
f
|
213
|
+
end
|
214
|
+
|
215
|
+
# Creates a class to wrap the C struct described by +signature+.
|
216
|
+
#
|
217
|
+
# MyStruct = struct ['int i', 'char c']
|
218
|
+
def struct(signature)
|
219
|
+
tys, mems = parse_struct_signature(signature, type_alias)
|
220
|
+
Fiddle::CStructBuilder.create(CStruct, tys, mems)
|
221
|
+
end
|
222
|
+
|
223
|
+
# Creates a class to wrap the C union described by +signature+.
|
224
|
+
#
|
225
|
+
# MyUnion = union ['int i', 'char c']
|
226
|
+
def union(signature)
|
227
|
+
tys, mems = parse_struct_signature(signature, type_alias)
|
228
|
+
Fiddle::CStructBuilder.create(CUnion, tys, mems)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns the function mapped to +name+, that was created by either
|
232
|
+
# Fiddle::Importer.extern or Fiddle::Importer.bind
|
233
|
+
def [](name)
|
234
|
+
@func_map[name]
|
235
|
+
end
|
236
|
+
|
237
|
+
# Creates a class to wrap the C struct with the value +ty+
|
238
|
+
#
|
239
|
+
# See also Fiddle::Importer.struct
|
240
|
+
def create_value(ty, val=nil)
|
241
|
+
s = struct([ty + " value"])
|
242
|
+
ptr = s.malloc()
|
243
|
+
if( val )
|
244
|
+
ptr.value = val
|
245
|
+
end
|
246
|
+
return ptr
|
247
|
+
end
|
248
|
+
alias value create_value
|
249
|
+
|
250
|
+
# Returns a new instance of the C struct with the value +ty+ at the +addr+
|
251
|
+
# address.
|
252
|
+
def import_value(ty, addr)
|
253
|
+
s = struct([ty + " value"])
|
254
|
+
ptr = s.new(addr)
|
255
|
+
return ptr
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
# The Fiddle::CompositeHandler instance
|
260
|
+
#
|
261
|
+
# Will raise an error if no handlers are open.
|
262
|
+
def handler
|
263
|
+
(@handler ||= nil) or raise "call dlload before importing symbols and functions"
|
264
|
+
end
|
265
|
+
|
266
|
+
# Returns a new Fiddle::Pointer instance at the memory address of the given
|
267
|
+
# +name+ symbol.
|
268
|
+
#
|
269
|
+
# Raises a DLError if the +name+ doesn't exist.
|
270
|
+
#
|
271
|
+
# See Fiddle::CompositeHandler.sym and Fiddle::Handle.sym
|
272
|
+
def import_symbol(name)
|
273
|
+
addr = handler.sym(name)
|
274
|
+
if( !addr )
|
275
|
+
raise(DLError, "cannot find the symbol: #{name}")
|
276
|
+
end
|
277
|
+
Pointer.new(addr)
|
278
|
+
end
|
279
|
+
|
280
|
+
# Returns a new Fiddle::Function instance at the memory address of the given
|
281
|
+
# +name+ function.
|
282
|
+
#
|
283
|
+
# Raises a DLError if the +name+ doesn't exist.
|
284
|
+
#
|
285
|
+
# * +argtype+ is an Array of arguments, passed to the +name+ function.
|
286
|
+
# * +ctype+ is the return type of the function
|
287
|
+
# * +call_type+ is the ABI of the function
|
288
|
+
#
|
289
|
+
# See also Fiddle:Function.new
|
290
|
+
#
|
291
|
+
# See Fiddle::CompositeHandler.sym and Fiddle::Handler.sym
|
292
|
+
def import_function(name, ctype, argtype, call_type = nil)
|
293
|
+
addr = handler.sym(name)
|
294
|
+
if( !addr )
|
295
|
+
raise(DLError, "cannot find the function: #{name}()")
|
296
|
+
end
|
297
|
+
Function.new(addr, argtype, ctype, CALL_TYPE_TO_ABI[call_type],
|
298
|
+
name: name)
|
299
|
+
end
|
300
|
+
|
301
|
+
# Returns a new closure wrapper for the +name+ function.
|
302
|
+
#
|
303
|
+
# * +ctype+ is the return type of the function
|
304
|
+
# * +argtype+ is an Array of arguments, passed to the callback function
|
305
|
+
# * +call_type+ is the abi of the closure
|
306
|
+
# * +block+ is passed to the callback
|
307
|
+
#
|
308
|
+
# See Fiddle::Closure
|
309
|
+
def bind_function(name, ctype, argtype, call_type = nil, &block)
|
310
|
+
abi = CALL_TYPE_TO_ABI[call_type]
|
311
|
+
closure = Class.new(Fiddle::Closure) {
|
312
|
+
define_method(:call, block)
|
313
|
+
}.new(ctype, argtype, abi)
|
314
|
+
|
315
|
+
Function.new(closure, argtype, ctype, abi, name: name)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|