fiddle 1.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|