fiddle 1.0.0.beta2 → 1.0.4

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.
@@ -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 */