fiddle 1.0.0.beta1 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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 */
|