fiddle 1.0.0.beta1 → 1.0.3
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 +5 -5
- data/LICENSE.txt +20 -19
- data/README.md +74 -6
- data/Rakefile +4 -6
- data/bin/downloader.rb +331 -0
- data/bin/extlibs.rb +262 -0
- data/ext/fiddle/closure.c +6 -5
- data/ext/fiddle/conversions.c +161 -16
- data/ext/fiddle/conversions.h +14 -4
- data/ext/fiddle/depend +83 -0
- data/ext/fiddle/extconf.rb +68 -31
- data/ext/fiddle/extlibs +13 -2
- data/ext/fiddle/fiddle.c +46 -35
- data/ext/fiddle/fiddle.h +35 -1
- data/ext/fiddle/function.c +220 -81
- data/ext/fiddle/handle.c +10 -12
- data/ext/fiddle/pinned.c +123 -0
- data/ext/fiddle/pointer.c +106 -24
- data/ext/fiddle/win32/fficonfig.h +0 -0
- data/ext/fiddle/win32/libffi-config.rb +2 -2
- data/ext/fiddle/win32/libffi.mk.tmpl +0 -0
- data/fiddle.gemspec +50 -8
- data/lib/fiddle.rb +4 -2
- data/lib/fiddle/closure.rb +1 -1
- data/lib/fiddle/cparser.rb +33 -3
- data/lib/fiddle/function.rb +1 -1
- data/lib/fiddle/import.rb +12 -10
- data/lib/fiddle/pack.rb +16 -9
- data/lib/fiddle/struct.rb +268 -44
- data/lib/fiddle/types.rb +1 -1
- data/lib/fiddle/value.rb +19 -10
- data/lib/fiddle/version.rb +3 -0
- metadata +18 -30
- data/.gitignore +0 -12
- data/.travis.yml +0 -5
- data/Gemfile +0 -4
- data/bin/console +0 -14
- data/bin/setup +0 -8
data/bin/extlibs.rb
ADDED
@@ -0,0 +1,262 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# Used to download, extract and patch extension libraries (extlibs)
|
4
|
+
# for Ruby. See common.mk for Ruby's usage.
|
5
|
+
|
6
|
+
require 'digest'
|
7
|
+
require_relative 'downloader'
|
8
|
+
|
9
|
+
class Vars < Hash
|
10
|
+
def pattern
|
11
|
+
/\$\((#{Regexp.union(keys)})\)/
|
12
|
+
end
|
13
|
+
|
14
|
+
def expand(str)
|
15
|
+
if empty?
|
16
|
+
str
|
17
|
+
else
|
18
|
+
str.gsub(pattern) {self[$1]}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class ExtLibs
|
24
|
+
def cache_file(url, cache_dir)
|
25
|
+
Downloader.cache_file(url, nil, :cache_dir => cache_dir)
|
26
|
+
end
|
27
|
+
|
28
|
+
def do_download(url, cache_dir)
|
29
|
+
Downloader.download(url, nil, nil, nil, :cache_dir => cache_dir)
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_checksum(cache, chksums)
|
33
|
+
chksums.each do |sum|
|
34
|
+
name, sum = sum.split(/:/)
|
35
|
+
if $VERBOSE
|
36
|
+
$stdout.print "checking #{name} of #{cache} ..."
|
37
|
+
$stdout.flush
|
38
|
+
end
|
39
|
+
hd = Digest(name.upcase).file(cache).hexdigest
|
40
|
+
if hd == sum
|
41
|
+
if $VERBOSE
|
42
|
+
$stdout.puts " OK"
|
43
|
+
$stdout.flush
|
44
|
+
end
|
45
|
+
else
|
46
|
+
if $VERBOSE
|
47
|
+
$stdout.puts " NG"
|
48
|
+
$stdout.flush
|
49
|
+
end
|
50
|
+
raise "checksum mismatch: #{cache}, #{name}:#{hd}, expected #{sum}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def do_extract(cache, dir)
|
56
|
+
if $VERBOSE
|
57
|
+
$stdout.puts "extracting #{cache} into #{dir}"
|
58
|
+
$stdout.flush
|
59
|
+
end
|
60
|
+
ext = File.extname(cache)
|
61
|
+
case ext
|
62
|
+
when '.gz', '.tgz'
|
63
|
+
f = IO.popen(["gzip", "-dc", cache])
|
64
|
+
cache = cache.chomp('.gz')
|
65
|
+
when '.bz2', '.tbz'
|
66
|
+
f = IO.popen(["bzip2", "-dc", cache])
|
67
|
+
cache = cache.chomp('.bz2')
|
68
|
+
when '.xz', '.txz'
|
69
|
+
f = IO.popen(["xz", "-dc", cache])
|
70
|
+
cache = cache.chomp('.xz')
|
71
|
+
else
|
72
|
+
inp = cache
|
73
|
+
end
|
74
|
+
inp ||= f.binmode
|
75
|
+
ext = File.extname(cache)
|
76
|
+
case ext
|
77
|
+
when '.tar', /\A\.t[gbx]z\z/
|
78
|
+
pid = Process.spawn("tar", "xpf", "-", in: inp, chdir: dir)
|
79
|
+
when '.zip'
|
80
|
+
pid = Process.spawn("unzip", inp, "-d", dir)
|
81
|
+
end
|
82
|
+
f.close if f
|
83
|
+
Process.wait(pid)
|
84
|
+
$?.success? or raise "failed to extract #{cache}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def do_patch(dest, patch, args)
|
88
|
+
if $VERBOSE
|
89
|
+
$stdout.puts "applying #{patch} under #{dest}"
|
90
|
+
$stdout.flush
|
91
|
+
end
|
92
|
+
Process.wait(Process.spawn("patch", "-d", dest, "-i", patch, *args))
|
93
|
+
$?.success? or raise "failed to patch #{patch}"
|
94
|
+
end
|
95
|
+
|
96
|
+
def do_link(file, src, dest)
|
97
|
+
file = File.join(dest, file)
|
98
|
+
if (target = src).start_with?("/")
|
99
|
+
target = File.join([".."] * file.count("/"), src)
|
100
|
+
end
|
101
|
+
return unless File.exist?(File.expand_path(target, File.dirname(file)))
|
102
|
+
File.unlink(file) rescue nil
|
103
|
+
begin
|
104
|
+
File.symlink(target, file)
|
105
|
+
rescue
|
106
|
+
else
|
107
|
+
if $VERBOSE
|
108
|
+
$stdout.puts "linked #{target} to #{file}"
|
109
|
+
$stdout.flush
|
110
|
+
end
|
111
|
+
return
|
112
|
+
end
|
113
|
+
begin
|
114
|
+
src = src.sub(/\A\//, '')
|
115
|
+
File.copy_stream(src, file)
|
116
|
+
rescue
|
117
|
+
if $VERBOSE
|
118
|
+
$stdout.puts "failed to link #{src} to #{file}: #{$!.message}"
|
119
|
+
end
|
120
|
+
else
|
121
|
+
if $VERBOSE
|
122
|
+
$stdout.puts "copied #{src} to #{file}"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def do_exec(command, dir, dest)
|
128
|
+
dir = dir ? File.join(dest, dir) : dest
|
129
|
+
if $VERBOSE
|
130
|
+
$stdout.puts "running #{command.dump} under #{dir}"
|
131
|
+
$stdout.flush
|
132
|
+
end
|
133
|
+
system(command, chdir: dir) or raise "failed #{command.dump}"
|
134
|
+
end
|
135
|
+
|
136
|
+
def do_command(mode, dest, url, cache_dir, chksums)
|
137
|
+
extracted = false
|
138
|
+
base = /.*(?=\.tar(?:\.\w+)?\z)/
|
139
|
+
|
140
|
+
case mode
|
141
|
+
when :download
|
142
|
+
cache = do_download(url, cache_dir)
|
143
|
+
do_checksum(cache, chksums)
|
144
|
+
when :extract
|
145
|
+
cache = cache_file(url, cache_dir)
|
146
|
+
target = File.join(dest, File.basename(cache)[base])
|
147
|
+
unless File.directory?(target)
|
148
|
+
do_checksum(cache, chksums)
|
149
|
+
extracted = do_extract(cache, dest)
|
150
|
+
end
|
151
|
+
when :all
|
152
|
+
cache = do_download(url, cache_dir)
|
153
|
+
target = File.join(dest, File.basename(cache)[base])
|
154
|
+
unless File.directory?(target)
|
155
|
+
do_checksum(cache, chksums)
|
156
|
+
extracted = do_extract(cache, dest)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
extracted
|
160
|
+
end
|
161
|
+
|
162
|
+
def run(argv)
|
163
|
+
cache_dir = nil
|
164
|
+
mode = :all
|
165
|
+
until argv.empty?
|
166
|
+
case argv[0]
|
167
|
+
when '--download'
|
168
|
+
mode = :download
|
169
|
+
when '--extract'
|
170
|
+
mode = :extract
|
171
|
+
when '--patch'
|
172
|
+
mode = :patch
|
173
|
+
when '--all'
|
174
|
+
mode = :all
|
175
|
+
when '--cache'
|
176
|
+
argv.shift
|
177
|
+
cache_dir = argv[0]
|
178
|
+
when /\A--cache=/
|
179
|
+
cache_dir = $'
|
180
|
+
when '--'
|
181
|
+
argv.shift
|
182
|
+
break
|
183
|
+
when /\A-/
|
184
|
+
warn "unknown option: #{argv[0]}"
|
185
|
+
return false
|
186
|
+
else
|
187
|
+
break
|
188
|
+
end
|
189
|
+
argv.shift
|
190
|
+
end
|
191
|
+
|
192
|
+
success = true
|
193
|
+
argv.each do |dir|
|
194
|
+
Dir.glob("#{dir}/**/extlibs") do |list|
|
195
|
+
if $VERBOSE
|
196
|
+
$stdout.puts "downloading for #{list}"
|
197
|
+
$stdout.flush
|
198
|
+
end
|
199
|
+
vars = Vars.new
|
200
|
+
extracted = false
|
201
|
+
dest = File.dirname(list)
|
202
|
+
url = chksums = nil
|
203
|
+
IO.foreach(list) do |line|
|
204
|
+
line.sub!(/\s*#.*/, '')
|
205
|
+
if /^(\w+)\s*=\s*(.*)/ =~ line
|
206
|
+
vars[$1] = vars.expand($2)
|
207
|
+
next
|
208
|
+
end
|
209
|
+
if chksums
|
210
|
+
chksums.concat(line.split)
|
211
|
+
elsif /^\t/ =~ line
|
212
|
+
if extracted and (mode == :all or mode == :patch)
|
213
|
+
patch, *args = line.split.map {|s| vars.expand(s)}
|
214
|
+
do_patch(dest, patch, args)
|
215
|
+
end
|
216
|
+
next
|
217
|
+
elsif /^!\s*(?:chdir:\s*([^|\s]+)\|\s*)?(.*)/ =~ line
|
218
|
+
if extracted and (mode == :all or mode == :patch)
|
219
|
+
command = vars.expand($2.strip)
|
220
|
+
chdir = $1 and chdir = vars.expand(chdir)
|
221
|
+
do_exec(command, chdir, dest)
|
222
|
+
end
|
223
|
+
next
|
224
|
+
elsif /->/ =~ line
|
225
|
+
if extracted and (mode == :all or mode == :patch)
|
226
|
+
link, file = $`.strip, $'.strip
|
227
|
+
do_link(vars.expand(link), vars.expand(file), dest)
|
228
|
+
end
|
229
|
+
next
|
230
|
+
else
|
231
|
+
url, *chksums = line.split(' ')
|
232
|
+
end
|
233
|
+
if chksums.last == '\\'
|
234
|
+
chksums.pop
|
235
|
+
next
|
236
|
+
end
|
237
|
+
unless url
|
238
|
+
chksums = nil
|
239
|
+
next
|
240
|
+
end
|
241
|
+
url = vars.expand(url)
|
242
|
+
begin
|
243
|
+
extracted = do_command(mode, dest, url, cache_dir, chksums)
|
244
|
+
rescue => e
|
245
|
+
warn e.inspect
|
246
|
+
success = false
|
247
|
+
end
|
248
|
+
url = chksums = nil
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
success
|
253
|
+
end
|
254
|
+
|
255
|
+
def self.run(argv)
|
256
|
+
self.new.run(argv)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
if $0 == __FILE__
|
261
|
+
exit ExtLibs.run(ARGV)
|
262
|
+
end
|
data/ext/fiddle/closure.c
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#include <fiddle.h>
|
2
2
|
#include <ruby/thread.h>
|
3
3
|
|
4
|
-
int ruby_thread_has_gvl_p(void); /*
|
4
|
+
int ruby_thread_has_gvl_p(void); /* from internal.h */
|
5
5
|
|
6
6
|
VALUE cFiddleClosure;
|
7
7
|
|
@@ -13,11 +13,12 @@ typedef struct {
|
|
13
13
|
ffi_type **argv;
|
14
14
|
} fiddle_closure;
|
15
15
|
|
16
|
-
#if defined(
|
17
|
-
#elif defined(__OpenBSD__) || defined(__APPLE__) || defined(__linux__)
|
16
|
+
#if defined(__OpenBSD__)
|
18
17
|
# define USE_FFI_CLOSURE_ALLOC 0
|
19
|
-
#
|
20
|
-
|
18
|
+
#endif
|
19
|
+
|
20
|
+
#if defined(USE_FFI_CLOSURE_ALLOC)
|
21
|
+
#elif !defined(HAVE_FFI_CLOSURE_ALLOC)
|
21
22
|
# define USE_FFI_CLOSURE_ALLOC 0
|
22
23
|
#else
|
23
24
|
# define USE_FFI_CLOSURE_ALLOC 1
|
data/ext/fiddle/conversions.c
CHANGED
@@ -1,7 +1,115 @@
|
|
1
1
|
#include <fiddle.h>
|
2
2
|
|
3
|
+
VALUE
|
4
|
+
rb_fiddle_type_ensure(VALUE type)
|
5
|
+
{
|
6
|
+
VALUE original_type = type;
|
7
|
+
|
8
|
+
if (!RB_SYMBOL_P(type)) {
|
9
|
+
VALUE type_string = rb_check_string_type(type);
|
10
|
+
if (!NIL_P(type_string)) {
|
11
|
+
type = rb_to_symbol(type_string);
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
if (RB_SYMBOL_P(type)) {
|
16
|
+
ID type_id = rb_sym2id(type);
|
17
|
+
ID void_id;
|
18
|
+
ID voidp_id;
|
19
|
+
ID char_id;
|
20
|
+
ID short_id;
|
21
|
+
ID int_id;
|
22
|
+
ID long_id;
|
23
|
+
#ifdef TYPE_LONG_LONG
|
24
|
+
ID long_long_id;
|
25
|
+
#endif
|
26
|
+
ID float_id;
|
27
|
+
ID double_id;
|
28
|
+
ID variadic_id;
|
29
|
+
ID const_string_id;
|
30
|
+
ID size_t_id;
|
31
|
+
ID ssize_t_id;
|
32
|
+
ID ptrdiff_t_id;
|
33
|
+
ID intptr_t_id;
|
34
|
+
ID uintptr_t_id;
|
35
|
+
RUBY_CONST_ID(void_id, "void");
|
36
|
+
RUBY_CONST_ID(voidp_id, "voidp");
|
37
|
+
RUBY_CONST_ID(char_id, "char");
|
38
|
+
RUBY_CONST_ID(short_id, "short");
|
39
|
+
RUBY_CONST_ID(int_id, "int");
|
40
|
+
RUBY_CONST_ID(long_id, "long");
|
41
|
+
#ifdef TYPE_LONG_LONG
|
42
|
+
RUBY_CONST_ID(long_long_id, "long_long");
|
43
|
+
#endif
|
44
|
+
RUBY_CONST_ID(float_id, "float");
|
45
|
+
RUBY_CONST_ID(double_id, "double");
|
46
|
+
RUBY_CONST_ID(variadic_id, "variadic");
|
47
|
+
RUBY_CONST_ID(const_string_id, "const_string");
|
48
|
+
RUBY_CONST_ID(size_t_id, "size_t");
|
49
|
+
RUBY_CONST_ID(ssize_t_id, "ssize_t");
|
50
|
+
RUBY_CONST_ID(ptrdiff_t_id, "ptrdiff_t");
|
51
|
+
RUBY_CONST_ID(intptr_t_id, "intptr_t");
|
52
|
+
RUBY_CONST_ID(uintptr_t_id, "uintptr_t");
|
53
|
+
if (type_id == void_id) {
|
54
|
+
return INT2NUM(TYPE_VOID);
|
55
|
+
}
|
56
|
+
else if (type_id == voidp_id) {
|
57
|
+
return INT2NUM(TYPE_VOIDP);
|
58
|
+
}
|
59
|
+
else if (type_id == char_id) {
|
60
|
+
return INT2NUM(TYPE_CHAR);
|
61
|
+
}
|
62
|
+
else if (type_id == short_id) {
|
63
|
+
return INT2NUM(TYPE_SHORT);
|
64
|
+
}
|
65
|
+
else if (type_id == int_id) {
|
66
|
+
return INT2NUM(TYPE_INT);
|
67
|
+
}
|
68
|
+
else if (type_id == long_id) {
|
69
|
+
return INT2NUM(TYPE_LONG);
|
70
|
+
}
|
71
|
+
#ifdef TYPE_LONG_LONG
|
72
|
+
else if (type_id == long_long_id) {
|
73
|
+
return INT2NUM(TYPE_LONG_LONG);
|
74
|
+
}
|
75
|
+
#endif
|
76
|
+
else if (type_id == float_id) {
|
77
|
+
return INT2NUM(TYPE_FLOAT);
|
78
|
+
}
|
79
|
+
else if (type_id == double_id) {
|
80
|
+
return INT2NUM(TYPE_DOUBLE);
|
81
|
+
}
|
82
|
+
else if (type_id == variadic_id) {
|
83
|
+
return INT2NUM(TYPE_VARIADIC);
|
84
|
+
}
|
85
|
+
else if (type_id == const_string_id) {
|
86
|
+
return INT2NUM(TYPE_CONST_STRING);
|
87
|
+
}
|
88
|
+
else if (type_id == size_t_id) {
|
89
|
+
return INT2NUM(TYPE_SIZE_T);
|
90
|
+
}
|
91
|
+
else if (type_id == ssize_t_id) {
|
92
|
+
return INT2NUM(TYPE_SSIZE_T);
|
93
|
+
}
|
94
|
+
else if (type_id == ptrdiff_t_id) {
|
95
|
+
return INT2NUM(TYPE_PTRDIFF_T);
|
96
|
+
}
|
97
|
+
else if (type_id == intptr_t_id) {
|
98
|
+
return INT2NUM(TYPE_INTPTR_T);
|
99
|
+
}
|
100
|
+
else if (type_id == uintptr_t_id) {
|
101
|
+
return INT2NUM(TYPE_UINTPTR_T);
|
102
|
+
}
|
103
|
+
else {
|
104
|
+
type = original_type;
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
return rb_to_int(type);
|
109
|
+
}
|
110
|
+
|
3
111
|
ffi_type *
|
4
|
-
|
112
|
+
rb_fiddle_int_to_ffi_type(int type)
|
5
113
|
{
|
6
114
|
int signed_p = 1;
|
7
115
|
|
@@ -33,66 +141,90 @@ int_to_ffi_type(int type)
|
|
33
141
|
return &ffi_type_float;
|
34
142
|
case TYPE_DOUBLE:
|
35
143
|
return &ffi_type_double;
|
144
|
+
case TYPE_CONST_STRING:
|
145
|
+
return &ffi_type_pointer;
|
36
146
|
default:
|
37
147
|
rb_raise(rb_eRuntimeError, "unknown type %d", type);
|
38
148
|
}
|
39
149
|
return &ffi_type_pointer;
|
40
150
|
}
|
41
151
|
|
152
|
+
ffi_type *
|
153
|
+
int_to_ffi_type(int type)
|
154
|
+
{
|
155
|
+
return rb_fiddle_int_to_ffi_type(type);
|
156
|
+
}
|
157
|
+
|
42
158
|
void
|
43
|
-
|
159
|
+
rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
|
44
160
|
{
|
45
161
|
switch (type) {
|
46
162
|
case TYPE_VOID:
|
47
163
|
break;
|
48
164
|
case TYPE_VOIDP:
|
49
|
-
dst->pointer = NUM2PTR(rb_Integer(src));
|
165
|
+
dst->pointer = NUM2PTR(rb_Integer(*src));
|
50
166
|
break;
|
51
167
|
case TYPE_CHAR:
|
52
|
-
dst->schar = (signed char)NUM2INT(src);
|
168
|
+
dst->schar = (signed char)NUM2INT(*src);
|
53
169
|
break;
|
54
170
|
case -TYPE_CHAR:
|
55
|
-
dst->uchar = (unsigned char)NUM2UINT(src);
|
171
|
+
dst->uchar = (unsigned char)NUM2UINT(*src);
|
56
172
|
break;
|
57
173
|
case TYPE_SHORT:
|
58
|
-
dst->sshort = (unsigned short)NUM2INT(src);
|
174
|
+
dst->sshort = (unsigned short)NUM2INT(*src);
|
59
175
|
break;
|
60
176
|
case -TYPE_SHORT:
|
61
|
-
dst->sshort = (signed short)NUM2UINT(src);
|
177
|
+
dst->sshort = (signed short)NUM2UINT(*src);
|
62
178
|
break;
|
63
179
|
case TYPE_INT:
|
64
|
-
dst->sint = NUM2INT(src);
|
180
|
+
dst->sint = NUM2INT(*src);
|
65
181
|
break;
|
66
182
|
case -TYPE_INT:
|
67
|
-
dst->uint = NUM2UINT(src);
|
183
|
+
dst->uint = NUM2UINT(*src);
|
68
184
|
break;
|
69
185
|
case TYPE_LONG:
|
70
|
-
dst->slong = NUM2LONG(src);
|
186
|
+
dst->slong = NUM2LONG(*src);
|
71
187
|
break;
|
72
188
|
case -TYPE_LONG:
|
73
|
-
dst->ulong = NUM2ULONG(src);
|
189
|
+
dst->ulong = NUM2ULONG(*src);
|
74
190
|
break;
|
75
191
|
#if HAVE_LONG_LONG
|
76
192
|
case TYPE_LONG_LONG:
|
77
|
-
dst->slong_long = NUM2LL(src);
|
193
|
+
dst->slong_long = NUM2LL(*src);
|
78
194
|
break;
|
79
195
|
case -TYPE_LONG_LONG:
|
80
|
-
dst->ulong_long = NUM2ULL(src);
|
196
|
+
dst->ulong_long = NUM2ULL(*src);
|
81
197
|
break;
|
82
198
|
#endif
|
83
199
|
case TYPE_FLOAT:
|
84
|
-
dst->ffloat = (float)NUM2DBL(src);
|
200
|
+
dst->ffloat = (float)NUM2DBL(*src);
|
85
201
|
break;
|
86
202
|
case TYPE_DOUBLE:
|
87
|
-
dst->ddouble = NUM2DBL(src);
|
203
|
+
dst->ddouble = NUM2DBL(*src);
|
204
|
+
break;
|
205
|
+
case TYPE_CONST_STRING:
|
206
|
+
if (NIL_P(*src)) {
|
207
|
+
dst->pointer = NULL;
|
208
|
+
}
|
209
|
+
else {
|
210
|
+
dst->pointer = rb_string_value_cstr(src);
|
211
|
+
}
|
88
212
|
break;
|
89
213
|
default:
|
90
214
|
rb_raise(rb_eRuntimeError, "unknown type %d", type);
|
91
215
|
}
|
92
216
|
}
|
93
217
|
|
218
|
+
void
|
219
|
+
value_to_generic(int type, VALUE src, fiddle_generic *dst)
|
220
|
+
{
|
221
|
+
/* src isn't safe from GC when type is TYPE_CONST_STRING and src
|
222
|
+
* isn't String. */
|
223
|
+
rb_fiddle_value_to_generic(type, &src, dst);
|
224
|
+
}
|
225
|
+
|
94
226
|
VALUE
|
95
|
-
|
227
|
+
rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
|
96
228
|
{
|
97
229
|
int type = NUM2INT(rettype);
|
98
230
|
VALUE cPointer;
|
@@ -131,6 +263,13 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
|
|
131
263
|
return rb_float_new(retval.ffloat);
|
132
264
|
case TYPE_DOUBLE:
|
133
265
|
return rb_float_new(retval.ddouble);
|
266
|
+
case TYPE_CONST_STRING:
|
267
|
+
if (retval.pointer) {
|
268
|
+
return rb_str_new_cstr(retval.pointer);
|
269
|
+
}
|
270
|
+
else {
|
271
|
+
return Qnil;
|
272
|
+
}
|
134
273
|
default:
|
135
274
|
rb_raise(rb_eRuntimeError, "unknown type %d", type);
|
136
275
|
}
|
@@ -138,4 +277,10 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
|
|
138
277
|
UNREACHABLE;
|
139
278
|
}
|
140
279
|
|
280
|
+
VALUE
|
281
|
+
generic_to_value(VALUE rettype, fiddle_generic retval)
|
282
|
+
{
|
283
|
+
return rb_fiddle_generic_to_value(rettype, retval);
|
284
|
+
}
|
285
|
+
|
141
286
|
/* vim: set noet sw=4 sts=4 */
|