fiddle 1.0.0.beta2 → 1.0.4

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
@@ -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,159 @@
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
+ #ifdef TYPE_INT8_T
27
+ ID int8_t_id;
28
+ #endif
29
+ #ifdef TYPE_INT16_T
30
+ ID int16_t_id;
31
+ #endif
32
+ #ifdef TYPE_INT32_T
33
+ ID int32_t_id;
34
+ #endif
35
+ #ifdef TYPE_INT64_T
36
+ ID int64_t_id;
37
+ #endif
38
+ ID float_id;
39
+ ID double_id;
40
+ ID variadic_id;
41
+ ID const_string_id;
42
+ ID size_t_id;
43
+ ID ssize_t_id;
44
+ ID ptrdiff_t_id;
45
+ ID intptr_t_id;
46
+ ID uintptr_t_id;
47
+ RUBY_CONST_ID(void_id, "void");
48
+ RUBY_CONST_ID(voidp_id, "voidp");
49
+ RUBY_CONST_ID(char_id, "char");
50
+ RUBY_CONST_ID(short_id, "short");
51
+ RUBY_CONST_ID(int_id, "int");
52
+ RUBY_CONST_ID(long_id, "long");
53
+ #ifdef TYPE_LONG_LONG
54
+ RUBY_CONST_ID(long_long_id, "long_long");
55
+ #endif
56
+ #ifdef TYPE_INT8_T
57
+ RUBY_CONST_ID(int8_t_id, "int8_t");
58
+ #endif
59
+ #ifdef TYPE_INT16_T
60
+ RUBY_CONST_ID(int16_t_id, "int16_t");
61
+ #endif
62
+ #ifdef TYPE_INT32_T
63
+ RUBY_CONST_ID(int32_t_id, "int32_t");
64
+ #endif
65
+ #ifdef TYPE_INT64_T
66
+ RUBY_CONST_ID(int64_t_id, "int64_t");
67
+ #endif
68
+ RUBY_CONST_ID(float_id, "float");
69
+ RUBY_CONST_ID(double_id, "double");
70
+ RUBY_CONST_ID(variadic_id, "variadic");
71
+ RUBY_CONST_ID(const_string_id, "const_string");
72
+ RUBY_CONST_ID(size_t_id, "size_t");
73
+ RUBY_CONST_ID(ssize_t_id, "ssize_t");
74
+ RUBY_CONST_ID(ptrdiff_t_id, "ptrdiff_t");
75
+ RUBY_CONST_ID(intptr_t_id, "intptr_t");
76
+ RUBY_CONST_ID(uintptr_t_id, "uintptr_t");
77
+ if (type_id == void_id) {
78
+ return INT2NUM(TYPE_VOID);
79
+ }
80
+ else if (type_id == voidp_id) {
81
+ return INT2NUM(TYPE_VOIDP);
82
+ }
83
+ else if (type_id == char_id) {
84
+ return INT2NUM(TYPE_CHAR);
85
+ }
86
+ else if (type_id == short_id) {
87
+ return INT2NUM(TYPE_SHORT);
88
+ }
89
+ else if (type_id == int_id) {
90
+ return INT2NUM(TYPE_INT);
91
+ }
92
+ else if (type_id == long_id) {
93
+ return INT2NUM(TYPE_LONG);
94
+ }
95
+ #ifdef TYPE_LONG_LONG
96
+ else if (type_id == long_long_id) {
97
+ return INT2NUM(TYPE_LONG_LONG);
98
+ }
99
+ #endif
100
+ #ifdef TYPE_INT8_T
101
+ else if (type_id == int8_t_id) {
102
+ return INT2NUM(TYPE_INT8_T);
103
+ }
104
+ #endif
105
+ #ifdef TYPE_INT16_T
106
+ else if (type_id == int16_t_id) {
107
+ return INT2NUM(TYPE_INT16_T);
108
+ }
109
+ #endif
110
+ #ifdef TYPE_INT32_T
111
+ else if (type_id == int32_t_id) {
112
+ return INT2NUM(TYPE_INT32_T);
113
+ }
114
+ #endif
115
+ #ifdef TYPE_INT64_T
116
+ else if (type_id == int64_t_id) {
117
+ return INT2NUM(TYPE_INT64_T);
118
+ }
119
+ #endif
120
+ else if (type_id == float_id) {
121
+ return INT2NUM(TYPE_FLOAT);
122
+ }
123
+ else if (type_id == double_id) {
124
+ return INT2NUM(TYPE_DOUBLE);
125
+ }
126
+ else if (type_id == variadic_id) {
127
+ return INT2NUM(TYPE_VARIADIC);
128
+ }
129
+ else if (type_id == const_string_id) {
130
+ return INT2NUM(TYPE_CONST_STRING);
131
+ }
132
+ else if (type_id == size_t_id) {
133
+ return INT2NUM(TYPE_SIZE_T);
134
+ }
135
+ else if (type_id == ssize_t_id) {
136
+ return INT2NUM(TYPE_SSIZE_T);
137
+ }
138
+ else if (type_id == ptrdiff_t_id) {
139
+ return INT2NUM(TYPE_PTRDIFF_T);
140
+ }
141
+ else if (type_id == intptr_t_id) {
142
+ return INT2NUM(TYPE_INTPTR_T);
143
+ }
144
+ else if (type_id == uintptr_t_id) {
145
+ return INT2NUM(TYPE_UINTPTR_T);
146
+ }
147
+ else {
148
+ type = original_type;
149
+ }
150
+ }
151
+
152
+ return rb_to_int(type);
153
+ }
154
+
3
155
  ffi_type *
4
- int_to_ffi_type(int type)
156
+ rb_fiddle_int_to_ffi_type(int type)
5
157
  {
6
158
  int signed_p = 1;
7
159
 
@@ -33,66 +185,90 @@ int_to_ffi_type(int type)
33
185
  return &ffi_type_float;
34
186
  case TYPE_DOUBLE:
35
187
  return &ffi_type_double;
188
+ case TYPE_CONST_STRING:
189
+ return &ffi_type_pointer;
36
190
  default:
37
191
  rb_raise(rb_eRuntimeError, "unknown type %d", type);
38
192
  }
39
193
  return &ffi_type_pointer;
40
194
  }
41
195
 
196
+ ffi_type *
197
+ int_to_ffi_type(int type)
198
+ {
199
+ return rb_fiddle_int_to_ffi_type(type);
200
+ }
201
+
42
202
  void
43
- value_to_generic(int type, VALUE src, fiddle_generic * dst)
203
+ rb_fiddle_value_to_generic(int type, VALUE *src, fiddle_generic *dst)
44
204
  {
45
205
  switch (type) {
46
206
  case TYPE_VOID:
47
207
  break;
48
208
  case TYPE_VOIDP:
49
- dst->pointer = NUM2PTR(rb_Integer(src));
209
+ dst->pointer = NUM2PTR(rb_Integer(*src));
50
210
  break;
51
211
  case TYPE_CHAR:
52
- dst->schar = (signed char)NUM2INT(src);
212
+ dst->schar = (signed char)NUM2INT(*src);
53
213
  break;
54
214
  case -TYPE_CHAR:
55
- dst->uchar = (unsigned char)NUM2UINT(src);
215
+ dst->uchar = (unsigned char)NUM2UINT(*src);
56
216
  break;
57
217
  case TYPE_SHORT:
58
- dst->sshort = (unsigned short)NUM2INT(src);
218
+ dst->sshort = (unsigned short)NUM2INT(*src);
59
219
  break;
60
220
  case -TYPE_SHORT:
61
- dst->sshort = (signed short)NUM2UINT(src);
221
+ dst->sshort = (signed short)NUM2UINT(*src);
62
222
  break;
63
223
  case TYPE_INT:
64
- dst->sint = NUM2INT(src);
224
+ dst->sint = NUM2INT(*src);
65
225
  break;
66
226
  case -TYPE_INT:
67
- dst->uint = NUM2UINT(src);
227
+ dst->uint = NUM2UINT(*src);
68
228
  break;
69
229
  case TYPE_LONG:
70
- dst->slong = NUM2LONG(src);
230
+ dst->slong = NUM2LONG(*src);
71
231
  break;
72
232
  case -TYPE_LONG:
73
- dst->ulong = NUM2ULONG(src);
233
+ dst->ulong = NUM2ULONG(*src);
74
234
  break;
75
235
  #if HAVE_LONG_LONG
76
236
  case TYPE_LONG_LONG:
77
- dst->slong_long = NUM2LL(src);
237
+ dst->slong_long = NUM2LL(*src);
78
238
  break;
79
239
  case -TYPE_LONG_LONG:
80
- dst->ulong_long = NUM2ULL(src);
240
+ dst->ulong_long = NUM2ULL(*src);
81
241
  break;
82
242
  #endif
83
243
  case TYPE_FLOAT:
84
- dst->ffloat = (float)NUM2DBL(src);
244
+ dst->ffloat = (float)NUM2DBL(*src);
85
245
  break;
86
246
  case TYPE_DOUBLE:
87
- dst->ddouble = NUM2DBL(src);
247
+ dst->ddouble = NUM2DBL(*src);
248
+ break;
249
+ case TYPE_CONST_STRING:
250
+ if (NIL_P(*src)) {
251
+ dst->pointer = NULL;
252
+ }
253
+ else {
254
+ dst->pointer = rb_string_value_cstr(src);
255
+ }
88
256
  break;
89
257
  default:
90
258
  rb_raise(rb_eRuntimeError, "unknown type %d", type);
91
259
  }
92
260
  }
93
261
 
262
+ void
263
+ value_to_generic(int type, VALUE src, fiddle_generic *dst)
264
+ {
265
+ /* src isn't safe from GC when type is TYPE_CONST_STRING and src
266
+ * isn't String. */
267
+ rb_fiddle_value_to_generic(type, &src, dst);
268
+ }
269
+
94
270
  VALUE
95
- generic_to_value(VALUE rettype, fiddle_generic retval)
271
+ rb_fiddle_generic_to_value(VALUE rettype, fiddle_generic retval)
96
272
  {
97
273
  int type = NUM2INT(rettype);
98
274
  VALUE cPointer;
@@ -131,6 +307,13 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
131
307
  return rb_float_new(retval.ffloat);
132
308
  case TYPE_DOUBLE:
133
309
  return rb_float_new(retval.ddouble);
310
+ case TYPE_CONST_STRING:
311
+ if (retval.pointer) {
312
+ return rb_str_new_cstr(retval.pointer);
313
+ }
314
+ else {
315
+ return Qnil;
316
+ }
134
317
  default:
135
318
  rb_raise(rb_eRuntimeError, "unknown type %d", type);
136
319
  }
@@ -138,4 +321,10 @@ generic_to_value(VALUE rettype, fiddle_generic retval)
138
321
  UNREACHABLE;
139
322
  }
140
323
 
324
+ VALUE
325
+ generic_to_value(VALUE rettype, fiddle_generic retval)
326
+ {
327
+ return rb_fiddle_generic_to_value(rettype, retval);
328
+ }
329
+
141
330
  /* vim: set noet sw=4 sts=4 */