fiddle 1.0.0 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,8 +2,14 @@
2
2
  * $Id$
3
3
  */
4
4
 
5
+ #include <stdbool.h>
5
6
  #include <ruby/ruby.h>
6
7
  #include <ruby/io.h>
8
+
9
+ #ifdef HAVE_RUBY_MEMORY_VIEW_H
10
+ # include <ruby/memory_view.h>
11
+ #endif
12
+
7
13
  #include <ctype.h>
8
14
  #include <fiddle.h>
9
15
 
@@ -24,6 +30,7 @@ struct ptr_data {
24
30
  void *ptr;
25
31
  long size;
26
32
  freefunc_t free;
33
+ bool freed;
27
34
  VALUE wrap[2];
28
35
  };
29
36
 
@@ -57,14 +64,19 @@ fiddle_ptr_mark(void *ptr)
57
64
  }
58
65
 
59
66
  static void
60
- fiddle_ptr_free(void *ptr)
67
+ fiddle_ptr_free_ptr(void *ptr)
61
68
  {
62
69
  struct ptr_data *data = ptr;
63
- if (data->ptr) {
64
- if (data->free) {
65
- (*(data->free))(data->ptr);
66
- }
70
+ if (data->ptr && data->free && !data->freed) {
71
+ data->freed = true;
72
+ (*(data->free))(data->ptr);
67
73
  }
74
+ }
75
+
76
+ static void
77
+ fiddle_ptr_free(void *ptr)
78
+ {
79
+ fiddle_ptr_free_ptr(ptr);
68
80
  xfree(ptr);
69
81
  }
70
82
 
@@ -80,6 +92,38 @@ static const rb_data_type_t fiddle_ptr_data_type = {
80
92
  {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
81
93
  };
82
94
 
95
+ #ifdef FIDDLE_MEMORY_VIEW
96
+ static struct ptr_data *
97
+ fiddle_ptr_check_memory_view(VALUE obj)
98
+ {
99
+ struct ptr_data *data;
100
+ TypedData_Get_Struct(obj, struct ptr_data, &fiddle_ptr_data_type, data);
101
+ if (data->ptr == NULL || data->size == 0) return NULL;
102
+ return data;
103
+ }
104
+
105
+ static int
106
+ fiddle_ptr_memory_view_available_p(VALUE obj)
107
+ {
108
+ return fiddle_ptr_check_memory_view(obj) != NULL;
109
+ }
110
+
111
+ static int
112
+ fiddle_ptr_get_memory_view(VALUE obj, rb_memory_view_t *view, int flags)
113
+ {
114
+ struct ptr_data *data = fiddle_ptr_check_memory_view(obj);
115
+ rb_memory_view_init_as_byte_array(view, obj, data->ptr, data->size, true);
116
+
117
+ return 1;
118
+ }
119
+
120
+ static const rb_memory_view_entry_t fiddle_ptr_memory_view_entry = {
121
+ fiddle_ptr_get_memory_view,
122
+ NULL,
123
+ fiddle_ptr_memory_view_available_p
124
+ };
125
+ #endif
126
+
83
127
  static VALUE
84
128
  rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
85
129
  {
@@ -89,8 +133,8 @@ rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
89
133
  val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
90
134
  data->ptr = ptr;
91
135
  data->free = func;
136
+ data->freed = false;
92
137
  data->size = size;
93
- OBJ_TAINT(val);
94
138
 
95
139
  return val;
96
140
  }
@@ -102,13 +146,13 @@ rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
102
146
  }
103
147
 
104
148
  static VALUE
105
- rb_fiddle_ptr_malloc(long size, freefunc_t func)
149
+ rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
106
150
  {
107
151
  void *ptr;
108
152
 
109
153
  ptr = ruby_xmalloc((size_t)size);
110
154
  memset(ptr,0,(size_t)size);
111
- return rb_fiddle_ptr_new(ptr, size, func);
155
+ return rb_fiddle_ptr_new2(klass, ptr, size, func);
112
156
  }
113
157
 
114
158
  static void *
@@ -141,6 +185,7 @@ rb_fiddle_ptr_s_allocate(VALUE klass)
141
185
  data->ptr = 0;
142
186
  data->size = 0;
143
187
  data->free = 0;
188
+ data->freed = false;
144
189
 
145
190
  return obj;
146
191
  }
@@ -192,16 +237,53 @@ rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
192
237
  return Qnil;
193
238
  }
194
239
 
240
+ static VALUE
241
+ rb_fiddle_ptr_call_free(VALUE self);
242
+
195
243
  /*
196
244
  * call-seq:
197
- *
198
245
  * Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
246
+ * Fiddle::Pointer.malloc(size, freefunc) { |pointer| ... } => ...
247
+ *
248
+ * == Examples
249
+ *
250
+ * # Automatically freeing the pointer when the block is exited - recommended
251
+ * Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE) do |pointer|
252
+ * ...
253
+ * end
254
+ *
255
+ * # Manually freeing but relying on the garbage collector otherwise
256
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
257
+ * ...
258
+ * pointer.call_free
259
+ *
260
+ * # Relying on the garbage collector - may lead to unlimited memory allocated before freeing any, but safe
261
+ * pointer = Fiddle::Pointer.malloc(size, Fiddle::RUBY_FREE)
262
+ * ...
263
+ *
264
+ * # Only manually freeing
265
+ * pointer = Fiddle::Pointer.malloc(size)
266
+ * begin
267
+ * ...
268
+ * ensure
269
+ * Fiddle.free pointer
270
+ * end
271
+ *
272
+ * # No free function and no call to free - the native memory will leak if the pointer is garbage collected
273
+ * pointer = Fiddle::Pointer.malloc(size)
274
+ * ...
199
275
  *
200
276
  * Allocate +size+ bytes of memory and associate it with an optional
201
- * +freefunc+ that will be called when the pointer is garbage collected.
277
+ * +freefunc+.
278
+ *
279
+ * If a block is supplied, the pointer will be yielded to the block instead of
280
+ * being returned, and the return value of the block will be returned. A
281
+ * +freefunc+ must be supplied if a block is.
202
282
  *
203
- * +freefunc+ must be an address pointing to a function or an instance of
204
- * Fiddle::Function
283
+ * If a +freefunc+ is supplied it will be called once, when the pointer is
284
+ * garbage collected or when the block is left if a block is supplied or
285
+ * when the user calls +call_free+, whichever happens first. +freefunc+ must be
286
+ * an address pointing to a function or an instance of +Fiddle::Function+.
205
287
  */
206
288
  static VALUE
207
289
  rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
@@ -223,10 +305,17 @@ rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
223
305
  rb_bug("rb_fiddle_ptr_s_malloc");
224
306
  }
225
307
 
226
- obj = rb_fiddle_ptr_malloc(s,f);
308
+ obj = rb_fiddle_ptr_malloc(klass, s,f);
227
309
  if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
228
310
 
229
- return obj;
311
+ if (rb_block_given_p()) {
312
+ if (!f) {
313
+ rb_raise(rb_eArgError, "a free function must be supplied to Fiddle::Pointer.malloc when it is called with a block");
314
+ }
315
+ return rb_ensure(rb_yield, obj, rb_fiddle_ptr_call_free, obj);
316
+ } else {
317
+ return obj;
318
+ }
230
319
  }
231
320
 
232
321
  /*
@@ -351,6 +440,34 @@ rb_fiddle_ptr_free_get(VALUE self)
351
440
  return rb_fiddle_new_function(address, arg_types, ret_type);
352
441
  }
353
442
 
443
+ /*
444
+ * call-seq: call_free => nil
445
+ *
446
+ * Call the free function for this pointer. Calling more than once will do
447
+ * nothing. Does nothing if there is no free function attached.
448
+ */
449
+ static VALUE
450
+ rb_fiddle_ptr_call_free(VALUE self)
451
+ {
452
+ struct ptr_data *pdata;
453
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
454
+ fiddle_ptr_free_ptr(pdata);
455
+ return Qnil;
456
+ }
457
+
458
+ /*
459
+ * call-seq: freed? => bool
460
+ *
461
+ * Returns if the free function for this pointer has been called.
462
+ */
463
+ static VALUE
464
+ rb_fiddle_ptr_freed_p(VALUE self)
465
+ {
466
+ struct ptr_data *pdata;
467
+ TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
468
+ return pdata->freed ? Qtrue : Qfalse;
469
+ }
470
+
354
471
  /*
355
472
  * call-seq:
356
473
  *
@@ -376,11 +493,11 @@ rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
376
493
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
377
494
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
378
495
  case 0:
379
- val = rb_tainted_str_new2((char*)(data->ptr));
496
+ val = rb_str_new2((char*)(data->ptr));
380
497
  break;
381
498
  case 1:
382
499
  len = NUM2INT(arg1);
383
- val = rb_tainted_str_new((char*)(data->ptr), len);
500
+ val = rb_str_new((char*)(data->ptr), len);
384
501
  break;
385
502
  default:
386
503
  rb_bug("rb_fiddle_ptr_to_s");
@@ -414,11 +531,11 @@ rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
414
531
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
415
532
  switch (rb_scan_args(argc, argv, "01", &arg1)) {
416
533
  case 0:
417
- val = rb_tainted_str_new((char*)(data->ptr),data->size);
534
+ val = rb_str_new((char*)(data->ptr),data->size);
418
535
  break;
419
536
  case 1:
420
537
  len = NUM2INT(arg1);
421
- val = rb_tainted_str_new((char*)(data->ptr), len);
538
+ val = rb_str_new((char*)(data->ptr), len);
422
539
  break;
423
540
  default:
424
541
  rb_bug("rb_fiddle_ptr_to_str");
@@ -440,7 +557,7 @@ rb_fiddle_ptr_inspect(VALUE self)
440
557
 
441
558
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
442
559
  return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
443
- RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
560
+ RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
444
561
  }
445
562
 
446
563
  /*
@@ -542,7 +659,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
542
659
  struct ptr_data *data;
543
660
 
544
661
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
545
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
662
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
546
663
  switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
547
664
  case 1:
548
665
  offset = NUM2ULONG(arg0);
@@ -551,7 +668,7 @@ rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
551
668
  case 2:
552
669
  offset = NUM2ULONG(arg0);
553
670
  len = NUM2ULONG(arg1);
554
- retval = rb_tainted_str_new((char *)data->ptr + offset, len);
671
+ retval = rb_str_new((char *)data->ptr + offset, len);
555
672
  break;
556
673
  default:
557
674
  rb_bug("rb_fiddle_ptr_aref()");
@@ -580,7 +697,7 @@ rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
580
697
  struct ptr_data *data;
581
698
 
582
699
  TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
583
- if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
700
+ if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
584
701
  switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
585
702
  case 2:
586
703
  offset = NUM2ULONG(arg0);
@@ -661,7 +778,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
661
778
  wrap = 0;
662
779
  }
663
780
  else{
664
- rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
781
+ rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
665
782
  }
666
783
  }
667
784
  else{
@@ -669,7 +786,6 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
669
786
  if (num == val) wrap = 0;
670
787
  ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
671
788
  }
672
- OBJ_INFECT(ptr, val);
673
789
  if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
674
790
  return ptr;
675
791
  }
@@ -677,6 +793,7 @@ rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
677
793
  void
678
794
  Init_fiddle_pointer(void)
679
795
  {
796
+ #undef rb_intern
680
797
  id_to_ptr = rb_intern("to_ptr");
681
798
 
682
799
  /* Document-class: Fiddle::Pointer
@@ -692,6 +809,8 @@ Init_fiddle_pointer(void)
692
809
  rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
693
810
  rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
694
811
  rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
812
+ rb_define_method(rb_cPointer, "call_free", rb_fiddle_ptr_call_free, 0);
813
+ rb_define_method(rb_cPointer, "freed?", rb_fiddle_ptr_freed_p, 0);
695
814
  rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
696
815
  rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
697
816
  rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
@@ -713,6 +832,10 @@ Init_fiddle_pointer(void)
713
832
  rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
714
833
  rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
715
834
 
835
+ #ifdef FIDDLE_MEMORY_VIEW
836
+ rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
837
+ #endif
838
+
716
839
  /* Document-const: NULL
717
840
  *
718
841
  * A NULL pointer
File without changes
@@ -32,7 +32,7 @@ IO.foreach("#{srcdir}/configure.ac") do |line|
32
32
  end
33
33
  end
34
34
 
35
- builddir = srcdir == "." ? enable['builddir'] : "."
35
+ builddir = srcdir == "." ? (enable['builddir'] || ".") : "."
36
36
  conf['TARGET'] = /^x64/ =~ host ? "X86_WIN64" : "X86_WIN32"
37
37
 
38
38
  FileUtils.mkdir_p([builddir, "#{builddir}/include", "#{builddir}/src/x86"])
File without changes
@@ -1,23 +1,66 @@
1
1
  # frozen_string_literal: true
2
+
3
+ version_module = Module.new do
4
+ version_rb = File.join(__dir__, "lib/fiddle/version.rb")
5
+ module_eval(File.read(version_rb), version_rb, __LINE__)
6
+ end
7
+
2
8
  Gem::Specification.new do |spec|
3
9
  spec.name = "fiddle"
4
- spec.version = '1.0.0'
10
+ spec.version = version_module::Fiddle::VERSION
5
11
  spec.authors = ["Aaron Patterson", "SHIBATA Hiroshi"]
6
12
  spec.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
7
13
 
8
14
  spec.summary = %q{A libffi wrapper for Ruby.}
9
15
  spec.description = %q{A libffi wrapper for Ruby.}
10
16
  spec.homepage = "https://github.com/ruby/fiddle"
11
- spec.license = "BSD-2-Clause"
17
+ spec.licenses = ["Ruby", "BSD-2-Clause"]
12
18
 
13
- spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "ext/fiddle/closure.c", "ext/fiddle/closure.h", "ext/fiddle/conversions.c", "ext/fiddle/conversions.h", "ext/fiddle/extconf.rb", "ext/fiddle/extlibs", "ext/fiddle/fiddle.c", "ext/fiddle/fiddle.h", "ext/fiddle/function.c", "ext/fiddle/function.h", "ext/fiddle/handle.c", "ext/fiddle/pointer.c", "ext/fiddle/win32/fficonfig.h", "ext/fiddle/win32/libffi-3.2.1-mswin.patch", "ext/fiddle/win32/libffi-config.rb", "ext/fiddle/win32/libffi.mk.tmpl", "fiddle.gemspec", "lib/fiddle.rb", "lib/fiddle/closure.rb", "lib/fiddle/cparser.rb", "lib/fiddle/function.rb", "lib/fiddle/import.rb", "lib/fiddle/pack.rb", "lib/fiddle/struct.rb", "lib/fiddle/types.rb", "lib/fiddle/value.rb"]
14
- spec.bindir = "exe"
15
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.files = [
20
+ "LICENSE.txt",
21
+ "README.md",
22
+ "Rakefile",
23
+ "bin/downloader.rb",
24
+ "bin/extlibs.rb",
25
+ "ext/fiddle/closure.c",
26
+ "ext/fiddle/closure.h",
27
+ "ext/fiddle/conversions.c",
28
+ "ext/fiddle/conversions.h",
29
+ "ext/fiddle/depend",
30
+ "ext/fiddle/extconf.rb",
31
+ "ext/fiddle/extlibs",
32
+ "ext/fiddle/fiddle.c",
33
+ "ext/fiddle/fiddle.h",
34
+ "ext/fiddle/function.c",
35
+ "ext/fiddle/function.h",
36
+ "ext/fiddle/handle.c",
37
+ "ext/fiddle/memory_view.c",
38
+ "ext/fiddle/pinned.c",
39
+ "ext/fiddle/pointer.c",
40
+ "ext/fiddle/win32/fficonfig.h",
41
+ "ext/fiddle/win32/libffi-3.2.1-mswin.patch",
42
+ "ext/fiddle/win32/libffi-config.rb",
43
+ "ext/fiddle/win32/libffi.mk.tmpl",
44
+ "fiddle.gemspec",
45
+ "lib/fiddle.rb",
46
+ "lib/fiddle/closure.rb",
47
+ "lib/fiddle/cparser.rb",
48
+ "lib/fiddle/function.rb",
49
+ "lib/fiddle/import.rb",
50
+ "lib/fiddle/pack.rb",
51
+ "lib/fiddle/struct.rb",
52
+ "lib/fiddle/types.rb",
53
+ "lib/fiddle/value.rb",
54
+ "lib/fiddle/version.rb",
55
+ ]
16
56
  spec.require_paths = ["lib"]
57
+ spec.extensions = ["ext/fiddle/extconf.rb"]
17
58
 
18
59
  spec.required_ruby_version = ">= 2.3.0"
19
60
 
20
61
  spec.add_development_dependency "bundler"
21
62
  spec.add_development_dependency "rake"
22
63
  spec.add_development_dependency "rake-compiler"
64
+
65
+ spec.metadata["msys2_mingw_dependencies"] = "libffi"
23
66
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require 'fiddle.so'
3
- require 'fiddle/function'
4
4
  require 'fiddle/closure'
5
+ require 'fiddle/function'
6
+ require 'fiddle/version'
5
7
 
6
8
  module Fiddle
7
9
  if WINDOWS
@@ -35,12 +35,37 @@ module Fiddle
35
35
  def parse_struct_signature(signature, tymap=nil)
36
36
  if signature.is_a?(String)
37
37
  signature = split_arguments(signature, /[,;]/)
38
+ elsif signature.is_a?(Hash)
39
+ signature = [signature]
38
40
  end
39
41
  mems = []
40
42
  tys = []
41
43
  signature.each{|msig|
42
- msig = compact(msig)
44
+ msig = compact(msig) if msig.is_a?(String)
43
45
  case msig
46
+ when Hash
47
+ msig.each do |struct_name, struct_signature|
48
+ struct_name = struct_name.to_s if struct_name.is_a?(Symbol)
49
+ struct_name = compact(struct_name)
50
+ struct_count = nil
51
+ if struct_name =~ /^([\w\*\s]+)\[(\d+)\]$/
52
+ struct_count = $2.to_i
53
+ struct_name = $1
54
+ end
55
+ if struct_signature.respond_to?(:entity_class)
56
+ struct_type = struct_signature
57
+ else
58
+ parsed_struct = parse_struct_signature(struct_signature, tymap)
59
+ struct_type = CStructBuilder.create(CStruct, *parsed_struct)
60
+ end
61
+ if struct_count
62
+ ty = [struct_type, struct_count]
63
+ else
64
+ ty = struct_type
65
+ end
66
+ mems.push([struct_name, struct_type.members])
67
+ tys.push(ty)
68
+ end
44
69
  when /^[\w\*\s]+[\*\s](\w+)$/
45
70
  mems.push($1)
46
71
  tys.push(parse_ctype(msig, tymap))
@@ -128,50 +153,90 @@ module Fiddle
128
153
  return [parse_ctype(ty[0], tymap), ty[1]]
129
154
  when 'void'
130
155
  return TYPE_VOID
131
- when /^(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?$/
132
- if( defined?(TYPE_LONG_LONG) )
133
- return TYPE_LONG_LONG
134
- else
156
+ when /\A(?:(?:signed\s+)?long\s+long(?:\s+int\s+)?|int64_t)(?:\s+\w+)?\z/
157
+ unless Fiddle.const_defined?(:TYPE_LONG_LONG)
135
158
  raise(RuntimeError, "unsupported type: #{ty}")
136
159
  end
137
- when /^(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?$/
138
- if( defined?(TYPE_LONG_LONG) )
139
- return -TYPE_LONG_LONG
140
- else
160
+ return TYPE_LONG_LONG
161
+ when /\A(?:unsigned\s+long\s+long(?:\s+int\s+)?|uint64_t)(?:\s+\w+)?\z/
162
+ unless Fiddle.const_defined?(:TYPE_LONG_LONG)
141
163
  raise(RuntimeError, "unsupported type: #{ty}")
142
164
  end
143
- when /^(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?$/
165
+ return -TYPE_LONG_LONG
166
+ when /\A(?:signed\s+)?long(?:\s+int\s+)?(?:\s+\w+)?\z/
144
167
  return TYPE_LONG
145
- when /^unsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?$/
168
+ when /\Aunsigned\s+long(?:\s+int\s+)?(?:\s+\w+)?\z/
146
169
  return -TYPE_LONG
147
- when /^(?:signed\s+)?int(?:\s+\w+)?$/
170
+ when /\A(?:signed\s+)?int(?:\s+\w+)?\z/
148
171
  return TYPE_INT
149
- when /^(?:unsigned\s+int|uint)(?:\s+\w+)?$/
172
+ when /\A(?:unsigned\s+int|uint)(?:\s+\w+)?\z/
150
173
  return -TYPE_INT
151
- when /^(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?$/
174
+ when /\A(?:signed\s+)?short(?:\s+int\s+)?(?:\s+\w+)?\z/
152
175
  return TYPE_SHORT
153
- when /^unsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?$/
176
+ when /\Aunsigned\s+short(?:\s+int\s+)?(?:\s+\w+)?\z/
154
177
  return -TYPE_SHORT
155
- when /^(?:signed\s+)?char(?:\s+\w+)?$/
178
+ when /\A(?:signed\s+)?char(?:\s+\w+)?\z/
156
179
  return TYPE_CHAR
157
- when /^unsigned\s+char(?:\s+\w+)?$/
180
+ when /\Aunsigned\s+char(?:\s+\w+)?\z/
158
181
  return -TYPE_CHAR
159
- when /^float(?:\s+\w+)?$/
182
+ when /\Aint8_t(?:\s+\w+)?\z/
183
+ unless Fiddle.const_defined?(:TYPE_INT8_T)
184
+ raise(RuntimeError, "unsupported type: #{ty}")
185
+ end
186
+ return TYPE_INT8_T
187
+ when /\Auint8_t(?:\s+\w+)?\z/
188
+ unless Fiddle.const_defined?(:TYPE_INT8_T)
189
+ raise(RuntimeError, "unsupported type: #{ty}")
190
+ end
191
+ return -TYPE_INT8_T
192
+ when /\Aint16_t(?:\s+\w+)?\z/
193
+ unless Fiddle.const_defined?(:TYPE_INT16_T)
194
+ raise(RuntimeError, "unsupported type: #{ty}")
195
+ end
196
+ return TYPE_INT16_T
197
+ when /\Auint16_t(?:\s+\w+)?\z/
198
+ unless Fiddle.const_defined?(:TYPE_INT16_T)
199
+ raise(RuntimeError, "unsupported type: #{ty}")
200
+ end
201
+ return -TYPE_INT16_T
202
+ when /\Aint32_t(?:\s+\w+)?\z/
203
+ unless Fiddle.const_defined?(:TYPE_INT32_T)
204
+ raise(RuntimeError, "unsupported type: #{ty}")
205
+ end
206
+ return TYPE_INT32_T
207
+ when /\Auint32_t(?:\s+\w+)?\z/
208
+ unless Fiddle.const_defined?(:TYPE_INT32_T)
209
+ raise(RuntimeError, "unsupported type: #{ty}")
210
+ end
211
+ return -TYPE_INT32_T
212
+ when /\Aint64_t(?:\s+\w+)?\z/
213
+ unless Fiddle.const_defined?(:TYPE_INT64_T)
214
+ raise(RuntimeError, "unsupported type: #{ty}")
215
+ end
216
+ return TYPE_INT64_T
217
+ when /\Auint64_t(?:\s+\w+)?\z/
218
+ unless Fiddle.const_defined?(:TYPE_INT64_T)
219
+ raise(RuntimeError, "unsupported type: #{ty}")
220
+ end
221
+ return -TYPE_INT64_T
222
+ when /\Afloat(?:\s+\w+)?\z/
160
223
  return TYPE_FLOAT
161
- when /^double(?:\s+\w+)?$/
224
+ when /\Adouble(?:\s+\w+)?\z/
162
225
  return TYPE_DOUBLE
163
- when /^size_t(?:\s+\w+)?$/
226
+ when /\Asize_t(?:\s+\w+)?\z/
164
227
  return TYPE_SIZE_T
165
- when /^ssize_t(?:\s+\w+)?$/
228
+ when /\Assize_t(?:\s+\w+)?\z/
166
229
  return TYPE_SSIZE_T
167
- when /^ptrdiff_t(?:\s+\w+)?$/
230
+ when /\Aptrdiff_t(?:\s+\w+)?\z/
168
231
  return TYPE_PTRDIFF_T
169
- when /^intptr_t(?:\s+\w+)?$/
232
+ when /\Aintptr_t(?:\s+\w+)?\z/
170
233
  return TYPE_INTPTR_T
171
- when /^uintptr_t(?:\s+\w+)?$/
234
+ when /\Auintptr_t(?:\s+\w+)?\z/
172
235
  return TYPE_UINTPTR_T
173
236
  when /\*/, /\[[\s\d]*\]/
174
237
  return TYPE_VOIDP
238
+ when "..."
239
+ return TYPE_VARIADIC
175
240
  else
176
241
  ty = ty.split(' ', 2)[0]
177
242
  if( tymap[ty] )
@@ -186,7 +251,7 @@ module Fiddle
186
251
 
187
252
  def split_arguments(arguments, sep=',')
188
253
  return [] if arguments.strip == 'void'
189
- arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+)(?:#{sep}\s*|$)/).collect {|m| m[0]}
254
+ arguments.scan(/([\w\*\s]+\(\*\w*\)\(.*?\)|[\w\*\s\[\]]+|\.\.\.)(?:#{sep}\s*|\z)/).collect {|m| m[0]}
190
255
  end
191
256
 
192
257
  def compact(signature)