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.
@@ -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
@@ -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); /* for ext/fiddle/closure.c */
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(USE_FFI_CLOSURE_ALLOC)
17
- #elif defined(__OpenBSD__) || defined(__APPLE__) || defined(__linux__)
16
+ #if defined(__OpenBSD__)
18
17
  # define USE_FFI_CLOSURE_ALLOC 0
19
- #elif defined(RUBY_LIBFFI_MODVERSION) && RUBY_LIBFFI_MODVERSION < 3000005 && \
20
- (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_AMD64))
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
@@ -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
- int_to_ffi_type(int type)
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
- value_to_generic(int type, VALUE src, fiddle_generic * dst)
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
- generic_to_value(VALUE rettype, fiddle_generic retval)
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 */