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