ffi 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (59) hide show
  1. data/README.rdoc +51 -1
  2. data/Rakefile +34 -26
  3. data/ext/ffi_c/AbstractMemory.c +73 -70
  4. data/ext/ffi_c/AbstractMemory.h +8 -4
  5. data/ext/ffi_c/AutoPointer.c +8 -9
  6. data/ext/ffi_c/AutoPointer.h +2 -2
  7. data/ext/ffi_c/Buffer.c +19 -20
  8. data/ext/ffi_c/Callback.c +85 -33
  9. data/ext/ffi_c/Callback.h +11 -5
  10. data/ext/ffi_c/{NativeLibrary.c → DynamicLibrary.c} +83 -16
  11. data/ext/ffi_c/{NativeLibrary.h → DynamicLibrary.h} +1 -1
  12. data/ext/ffi_c/Invoker.c +148 -192
  13. data/ext/ffi_c/LastError.c +135 -0
  14. data/ext/ffi_c/LastError.h +18 -0
  15. data/ext/ffi_c/MemoryPointer.c +26 -19
  16. data/ext/ffi_c/MemoryPointer.h +3 -3
  17. data/ext/ffi_c/NullPointer.c +49 -47
  18. data/ext/ffi_c/Platform.c +9 -10
  19. data/ext/ffi_c/Platform.h +1 -1
  20. data/ext/ffi_c/Pointer.c +52 -21
  21. data/ext/ffi_c/Pointer.h +8 -6
  22. data/ext/ffi_c/Struct.c +70 -61
  23. data/ext/ffi_c/Struct.h +2 -2
  24. data/ext/ffi_c/Type.c +230 -0
  25. data/ext/ffi_c/Type.h +28 -0
  26. data/ext/ffi_c/Types.c +47 -6
  27. data/ext/ffi_c/Types.h +8 -2
  28. data/ext/ffi_c/endian.h +40 -0
  29. data/ext/ffi_c/extconf.rb +6 -5
  30. data/ext/ffi_c/ffi.c +20 -43
  31. data/ext/ffi_c/libffi.bsd.mk +34 -0
  32. data/ext/ffi_c/libffi.darwin.mk +30 -10
  33. data/ext/ffi_c/libffi.gnu.mk +29 -0
  34. data/ext/ffi_c/libffi.mk +4 -2
  35. data/ext/ffi_c/rbffi.h +6 -8
  36. data/lib/ffi.rb +10 -1
  37. data/lib/ffi/autopointer.rb +1 -1
  38. data/lib/ffi/enum.rb +78 -0
  39. data/lib/ffi/ffi.rb +5 -6
  40. data/lib/ffi/io.rb +15 -1
  41. data/lib/ffi/library.rb +78 -17
  42. data/lib/ffi/pointer.rb +2 -2
  43. data/lib/ffi/struct.rb +68 -14
  44. data/lib/ffi/types.rb +6 -3
  45. data/lib/ffi/variadic.rb +2 -2
  46. data/spec/ffi/bool_spec.rb +24 -0
  47. data/spec/ffi/callback_spec.rb +217 -17
  48. data/spec/ffi/enum_spec.rb +164 -0
  49. data/spec/ffi/managed_struct_spec.rb +6 -1
  50. data/spec/ffi/number_spec.rb +30 -0
  51. data/spec/ffi/pointer_spec.rb +33 -8
  52. data/spec/ffi/rbx/memory_pointer_spec.rb +0 -6
  53. data/spec/ffi/spec_helper.rb +5 -1
  54. data/spec/ffi/string_spec.rb +65 -4
  55. data/spec/ffi/struct_callback_spec.rb +41 -0
  56. data/spec/ffi/struct_initialize_spec.rb +30 -0
  57. data/spec/ffi/struct_spec.rb +19 -20
  58. metadata +29 -52
  59. data/ext/ffi_c/ffi.mk +0 -23
@@ -4,16 +4,66 @@ ruby-ffi
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- A Ruby foreign function interface
7
+ Ruby-FFI is a ruby extension for programmatically loading dynamic
8
+ libraries, binding functions within them, and calling those functions
9
+ from Ruby code. Moreover, a Ruby-FFI extension works without changes
10
+ on Ruby and JRuby. Discover why should you write your next extension
11
+ using Ruby-FFI {here}[http://kenai.com/projects/ruby-ffi/pages/WhyUseFFI].
8
12
 
9
13
  == FEATURES/PROBLEMS:
10
14
 
15
+ * It has a very intuitive DSL
16
+ * It supports all C native types
17
+ * It supports C structs (also nested), enums and global variables
18
+ * It supports callbacks
19
+ * It has smart methods to handle memory management of pointers and structs
20
+
11
21
  == SYNOPSIS:
12
22
 
23
+ require 'ffi'
24
+
25
+ module MyLib
26
+ extend FFI::Library
27
+ attach_function :puts, [ :string ], :int
28
+ end
29
+
30
+ MyLib.puts 'Hello boys using libc!'
31
+
32
+ For less minimalistic and more sane examples you may look at:
33
+
34
+ * the samples/ folder
35
+ * the examples on the Kenai {wiki}[http://kenai.com/projects/ruby-ffi/pages/Home]
36
+ * the projects using FFI listed on this {page}[http://kenai.com/projects/ruby-ffi/pages/ProjectsUsingFFI]
37
+
13
38
  == REQUIREMENTS:
14
39
 
40
+ * You need a sane building environment in order to compile the extension.
41
+
15
42
  == DOWNLOAD/INSTALL:
16
43
 
44
+ From rubyforge:
45
+
46
+ [sudo] gem install ffi
47
+
48
+ or from the mercurial repository on Kenai:
49
+
50
+ hg clone https://kenai.com/hg/ruby-ffi~mercurial ruby-ffi
51
+ cd ruby-ffi
52
+ rake gem:install
53
+
54
+ == CREDITS:
55
+
56
+ Special thanks to:
57
+
58
+ Yehuda Katz
59
+ Luc Heinrich
60
+ Andrea Fazzi
61
+ Mike Dalessio
62
+ Hongli Lai
63
+ Evan Phoenix
64
+ Aman Gupta
65
+ Beoran
66
+
17
67
  == LICENSE:
18
68
 
19
69
  See LICENSE file.
data/Rakefile CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'rubygems'
2
+ require 'rbconfig'
2
3
 
3
- USE_RAKE_COMPILER = (RUBY_VERSION =~ /1\.9.*/ || RUBY_PLATFORM =~ /java/) ? false : true
4
+ USE_RAKE_COMPILER = (RUBY_PLATFORM =~ /java/) ? false : true
4
5
  if USE_RAKE_COMPILER
5
- gem 'rake-compiler', '>=0.3.0'
6
+ gem 'rake-compiler', '>=0.6.0'
6
7
  require 'rake/extensiontask'
8
+ ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
7
9
  end
8
10
 
9
11
  require 'date'
@@ -24,20 +26,22 @@ end
24
26
  LIBEXT = Config::CONFIG['host_os'].downcase =~ /darwin/ ? "dylib" : "so"
25
27
  GMAKE = Config::CONFIG['host_os'].downcase =~ /bsd/ ? "gmake" : "make"
26
28
  LIBTEST = "build/libtest.#{LIBEXT}"
27
- BUILD_DIR = "build/#{RUBY_VERSION}"
29
+ BUILD_DIR = "build"
30
+ BUILD_EXT_DIR = File.join(BUILD_DIR, "#{Config::CONFIG['arch']}", 'ffi_c', RUBY_VERSION)
28
31
 
29
32
  # Project general information
30
33
  PROJ.name = 'ffi'
31
34
  PROJ.authors = 'Wayne Meissner'
32
35
  PROJ.email = 'wmeissner@gmail.com'
33
36
  PROJ.url = 'http://kenai.com/projects/ruby-ffi'
34
- PROJ.version = '0.3.5'
37
+ PROJ.version = '0.4.0'
35
38
  PROJ.rubyforge.name = 'ffi'
36
39
  PROJ.readme_file = 'README.rdoc'
37
40
 
38
41
  # Annoucement
39
- PROJ.ann.paragraphs
40
- PROJ.ann.email[:from] = 'wmeissner@gmail.com'
42
+ PROJ.ann.paragraphs << 'FEATURES' << 'SYNOPSIS' << 'REQUIREMENTS' << 'DOWNLOAD/INSTALL' << 'CREDITS' << 'LICENSE'
43
+
44
+ PROJ.ann.email[:from] = 'andrea.fazzi@alcacoop.it'
41
45
  PROJ.ann.email[:to] << 'dev@ruby-ffi.kenai.com' << 'users@ruby-ffi.kenai.com'
42
46
  PROJ.ann.email[:server] = 'smtp.gmail.com'
43
47
 
@@ -55,7 +59,7 @@ PROJ.rdoc.opts << '-x' << 'ext'
55
59
 
56
60
  # Ruby
57
61
  PROJ.ruby_opts = []
58
- PROJ.ruby_opts << '-I' << "\"#{BUILD_DIR}\"" unless RUBY_PLATFORM == "java"
62
+ PROJ.ruby_opts << '-I' << BUILD_EXT_DIR unless RUBY_PLATFORM == "java"
59
63
 
60
64
  #RSpec
61
65
  PROJ.spec.opts << '--color' << '-fs'
@@ -75,12 +79,12 @@ else
75
79
  desc "Run all specs"
76
80
  task :specs => TEST_DEPS do
77
81
  ENV["MRI_FFI"] = "1"
78
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
82
+ sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/*_spec.rb"].join(" ")} -fs --color}
79
83
  end
80
84
  desc "Run rubinius specs"
81
85
  task :rbxspecs => TEST_DEPS do
82
86
  ENV["MRI_FFI"] = "1"
83
- sh %{#{Gem.ruby} -Ilib -I#{BUILD_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
87
+ sh %{#{Gem.ruby} -Ilib -I#{BUILD_EXT_DIR} -S spec #{Dir["spec/ffi/rbx/*_spec.rb"].join(" ")} -fs --color}
84
88
  end
85
89
  end
86
90
 
@@ -90,30 +94,31 @@ task :package => 'gem:package'
90
94
  desc "Install the gem locally"
91
95
  task :install => 'gem:install'
92
96
 
93
- unless USE_RAKE_COMPILER
94
- file "#{BUILD_DIR}/Makefile" do
95
- FileUtils.mkdir_p(BUILD_DIR) unless File.directory?(BUILD_DIR)
96
- sh %{cd "#{BUILD_DIR}" && #{Gem.ruby} #{Dir.pwd}/ext/ffi_c/extconf.rb}
97
- end
98
- desc "Compile the native module"
99
- task :compile => "#{BUILD_DIR}/Makefile" do
100
- sh %{cd "#{BUILD_DIR}"; make}
101
- end
102
- end
97
+
103
98
  desc "Clean all built files"
104
- task :clean do
105
- FileUtils.rm_rf("build")
106
- FileUtils.rm_rf("conftest.dSYM")
107
- FileUtils.rm_f(Dir["pkg/*.gem"])
99
+ task :distclean => :clobber do
100
+ FileUtils.rm_rf('build')
101
+ FileUtils.rm_rf(Dir['lib/**/ffi_c.so'])
102
+ FileUtils.rm_rf('lib/1.8')
103
+ FileUtils.rm_rf('lib/1.9')
104
+ FileUtils.rm_rf('conftest.dSYM')
105
+ FileUtils.rm_rf('pkg')
108
106
  end
107
+
108
+
109
+ desc "Build the native test lib"
109
110
  task "build/libtest.#{LIBEXT}" do
110
- sh %{#{GMAKE} -f libtest/GNUmakefile}
111
+ sh %{#{GMAKE} -f libtest/GNUmakefile CPU=#{Config::CONFIG['host_cpu']}}
111
112
  end
113
+
114
+
112
115
  desc "Build test helper lib"
113
116
  task :libtest => "build/libtest.#{LIBEXT}"
117
+
114
118
  desc "Test the extension"
115
- task :test => [ :specs, :rbxspecs ] do
116
- end
119
+ task :test => [ :specs, :rbxspecs ]
120
+
121
+
117
122
  namespace :bench do
118
123
  ITER = ENV['ITER'] ? ENV['ITER'].to_i : 100000
119
124
  bench_libs = "-Ilib -I#{BUILD_DIR}" unless RUBY_PLATFORM == "java"
@@ -132,3 +137,6 @@ end
132
137
 
133
138
  task 'spec:run' => TEST_DEPS
134
139
  task 'spec:specdoc' => TEST_DEPS
140
+
141
+ task :default => :specs
142
+
@@ -11,9 +11,9 @@
11
11
 
12
12
 
13
13
  static inline char* memory_address(VALUE self);
14
- VALUE rb_FFI_AbstractMemory_class = Qnil;
15
- static VALUE classMemory = Qnil;
16
- static ID to_ptr = 0;
14
+ VALUE rbffi_AbstractMemoryClass = Qnil;
15
+ static ID id_to_ptr = 0;
16
+ static ID id_call = 0;
17
17
 
18
18
  static VALUE
19
19
  memory_allocate(VALUE klass)
@@ -21,7 +21,7 @@ memory_allocate(VALUE klass)
21
21
  AbstractMemory* memory;
22
22
  VALUE obj;
23
23
  obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
24
- memory->ops = &rb_FFI_AbstractMemory_ops;
24
+ memory->ops = &rbffi_AbstractMemoryOps;
25
25
 
26
26
  return obj;
27
27
  }
@@ -107,63 +107,26 @@ NUM_OP(uint64, uint64_t, NUM2ULL, ULL2NUM);
107
107
  NUM_OP(float32, float, NUM2DBL, rb_float_new);
108
108
  NUM_OP(float64, double, NUM2DBL, rb_float_new);
109
109
 
110
- static void
111
- memory_op_put_pointer(AbstractMemory* memory, long off, VALUE value)
112
- {
110
+ static inline void*
111
+ get_pointer_value(VALUE value)
112
+ {
113
113
  const int type = TYPE(value);
114
- checkBounds(memory, off, sizeof(void *));
115
-
116
- if (rb_obj_is_kind_of(value, rb_FFI_Pointer_class) && type == T_DATA) {
117
- void* tmp = memory_address(value);
118
- memcpy(memory->address + off, &tmp, sizeof(tmp));
114
+ if (type == T_DATA && rb_obj_is_kind_of(value, rbffi_PointerClass)) {
115
+ return memory_address(value);
119
116
  } else if (type == T_NIL) {
120
- void* tmp = NULL;
121
- memcpy(memory->address + off, &tmp, sizeof(tmp));
117
+ return NULL;
122
118
  } else if (type == T_FIXNUM) {
123
- uintptr_t tmp = (uintptr_t) FIX2INT(value);
124
- memcpy(memory->address + off, &tmp, sizeof(tmp));
119
+ return (void *) (uintptr_t) FIX2INT(value);
125
120
  } else if (type == T_BIGNUM) {
126
- uintptr_t tmp = (uintptr_t) NUM2ULL(value);
127
- memcpy(memory->address + off, &tmp, sizeof(tmp));
128
- } else if (rb_respond_to(value, to_ptr)) {
129
- VALUE ptr = rb_funcall2(value, to_ptr, 0, NULL);
130
- void* tmp = MEMORY_PTR(ptr);
131
- memcpy(memory->address + off, &tmp, sizeof(tmp));
121
+ return (void *) (uintptr_t) NUM2ULL(value);
122
+ } else if (rb_respond_to(value, id_to_ptr)) {
123
+ return MEMORY_PTR(rb_funcall2(value, id_to_ptr, 0, NULL));
132
124
  } else {
133
125
  rb_raise(rb_eArgError, "value is not a pointer");
134
126
  }
135
127
  }
136
128
 
137
- static VALUE
138
- memory_op_get_pointer(AbstractMemory* memory, long off)
139
- {
140
- void* tmp;
141
-
142
- checkBounds(memory, off, sizeof(tmp));
143
- memcpy(&tmp, memory->address + off, sizeof(tmp));
144
- return rb_FFI_Pointer_new(tmp);
145
- }
146
-
147
- static VALUE
148
- memory_put_pointer(VALUE self, VALUE offset, VALUE value)
149
- {
150
- AbstractMemory* memory;
151
-
152
- Data_Get_Struct(self, AbstractMemory, memory);
153
- memory_op_put_pointer(memory, NUM2LONG(offset), value);
154
-
155
- return self;
156
- }
157
-
158
- static VALUE
159
- memory_get_pointer(VALUE self, VALUE offset)
160
- {
161
- AbstractMemory* memory;
162
-
163
- Data_Get_Struct(self, AbstractMemory, memory);
164
-
165
- return memory_op_get_pointer(memory, NUM2LONG(offset));
166
- }
129
+ NUM_OP(pointer, void *, get_pointer_value, rbffi_Pointer_NewInstance);
167
130
 
168
131
  static VALUE
169
132
  memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
@@ -172,8 +135,8 @@ memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
172
135
  long off = NUM2LONG(offset);
173
136
  checkBounds(memory, off, sizeof(void *));
174
137
 
175
- if (rb_obj_is_kind_of(proc, rb_cProc)) {
176
- VALUE callback = rb_FFI_NativeCallback_for_proc(proc, cbInfo);
138
+ if (rb_obj_is_kind_of(proc, rb_cProc) || rb_respond_to(proc, id_call)) {
139
+ VALUE callback = rbffi_NativeCallback_ForProc(proc, cbInfo);
177
140
  void* code = ((NativeCallback *) DATA_PTR(callback))->code;
178
141
  memcpy(memory->address + off, &code, sizeof(code));
179
142
  } else {
@@ -214,6 +177,45 @@ memory_get_string(int argc, VALUE* argv, VALUE self)
214
177
  (end != NULL ? end - ptr->address - off : len));
215
178
  }
216
179
 
180
+ static VALUE
181
+ memory_get_array_of_string(int argc, VALUE* argv, VALUE self)
182
+ {
183
+ VALUE offset = Qnil, countnum = Qnil, retVal = Qnil;
184
+ AbstractMemory* ptr;
185
+ long off;
186
+ int count;
187
+
188
+ rb_scan_args(argc, argv, "11", &offset, &countnum);
189
+ off = NUM2LONG(offset);
190
+ count = (countnum == Qnil ? 0 : NUM2INT(countnum));
191
+ retVal = rb_ary_new2(count);
192
+
193
+ Data_Get_Struct(self, AbstractMemory, ptr);
194
+
195
+ if (countnum != Qnil) {
196
+ int i;
197
+
198
+ checkBounds(ptr, off, count * sizeof (char*));
199
+
200
+ for (i = 0; i < count; ++i) {
201
+ const char* strptr = *((const char**) (ptr->address + off) + i);
202
+ rb_ary_push(retVal, (strptr == NULL ? Qnil : rb_tainted_str_new2(strptr)));
203
+ }
204
+
205
+ } else {
206
+ checkBounds(ptr, off, sizeof (char*));
207
+ for ( ; off < ptr->size - sizeof (void *); off += sizeof (void *)) {
208
+ const char* strptr = *(const char**) (ptr->address + off);
209
+ if (strptr == NULL) {
210
+ break;
211
+ }
212
+ rb_ary_push(retVal, rb_tainted_str_new2(strptr));
213
+ }
214
+ }
215
+
216
+ return retVal;
217
+ }
218
+
217
219
  static VALUE
218
220
  memory_put_string(VALUE self, VALUE offset, VALUE str)
219
221
  {
@@ -224,7 +226,7 @@ memory_put_string(VALUE self, VALUE offset, VALUE str)
224
226
  off = NUM2LONG(offset);
225
227
  len = RSTRING_LEN(str);
226
228
 
227
- checkBounds(ptr, off, len);
229
+ checkBounds(ptr, off, len + 1);
228
230
  if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
229
231
  rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
230
232
  }
@@ -279,13 +281,14 @@ memory_address(VALUE obj)
279
281
  }
280
282
 
281
283
  AbstractMemory*
282
- rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass)
284
+ rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass)
283
285
  {
284
286
  if (rb_obj_is_kind_of(obj, klass)) {
285
287
  AbstractMemory* memory;
286
288
  Data_Get_Struct(obj, AbstractMemory, memory);
287
289
  return memory;
288
290
  }
291
+
289
292
  rb_raise(rb_eArgError, "Invalid Memory object");
290
293
  return NULL;
291
294
  }
@@ -311,9 +314,9 @@ memory_op_put_strptr(AbstractMemory* ptr, long offset, VALUE value)
311
314
 
312
315
  static MemoryOp memory_op_strptr = { memory_op_get_strptr, memory_op_put_strptr };
313
316
 
314
- static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
317
+ //static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
315
318
 
316
- MemoryOps rb_FFI_AbstractMemory_ops = {
319
+ MemoryOps rbffi_AbstractMemoryOps = {
317
320
  .int8 = &memory_op_int8,
318
321
  .uint8 = &memory_op_uint8,
319
322
  .int16 = &memory_op_int16,
@@ -329,10 +332,11 @@ MemoryOps rb_FFI_AbstractMemory_ops = {
329
332
  };
330
333
 
331
334
  void
332
- rb_FFI_AbstractMemory_Init()
335
+ rbffi_AbstractMemory_Init(VALUE moduleFFI)
333
336
  {
334
- VALUE moduleFFI = rb_define_module("FFI");
335
- rb_FFI_AbstractMemory_class = classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
337
+ VALUE classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
338
+ rbffi_AbstractMemoryClass = classMemory;
339
+ rb_global_variable(&rbffi_AbstractMemoryClass);
336
340
 
337
341
  rb_define_alloc_func(classMemory, memory_allocate);
338
342
  #undef INT
@@ -367,16 +371,11 @@ rb_FFI_AbstractMemory_Init()
367
371
  ALIAS(long_long, int64);
368
372
 
369
373
  if (sizeof(long) == 4) {
370
- rb_define_alias(classMemory, "put_long", "put_int32");
371
- rb_define_alias(classMemory, "put_ulong", "put_uint32");
372
- rb_define_alias(classMemory, "get_long", "get_int32");
373
- rb_define_alias(classMemory, "get_ulong", "get_uint32");
374
+ ALIAS(long, int32);
374
375
  } else {
375
- rb_define_alias(classMemory, "put_long", "put_int64");
376
- rb_define_alias(classMemory, "put_ulong", "put_uint64");
377
- rb_define_alias(classMemory, "get_long", "get_int64");
378
- rb_define_alias(classMemory, "get_ulong", "get_uint64");
376
+ ALIAS(long, int64);
379
377
  }
378
+
380
379
  rb_define_method(classMemory, "put_float32", memory_put_float32, 2);
381
380
  rb_define_method(classMemory, "get_float32", memory_get_float32, 1);
382
381
  rb_define_alias(classMemory, "put_float", "put_float32");
@@ -395,15 +394,19 @@ rb_FFI_AbstractMemory_Init()
395
394
  rb_define_alias(classMemory, "get_array_of_double", "get_array_of_float64");
396
395
  rb_define_method(classMemory, "put_pointer", memory_put_pointer, 2);
397
396
  rb_define_method(classMemory, "get_pointer", memory_get_pointer, 1);
397
+ rb_define_method(classMemory, "put_array_of_pointer", memory_put_array_of_pointer, 2);
398
+ rb_define_method(classMemory, "get_array_of_pointer", memory_get_array_of_pointer, 2);
398
399
  rb_define_method(classMemory, "put_callback", memory_put_callback, 3);
399
400
  rb_define_method(classMemory, "get_string", memory_get_string, -1);
400
401
  rb_define_method(classMemory, "put_string", memory_put_string, 2);
401
402
  rb_define_method(classMemory, "get_bytes", memory_get_bytes, 2);
402
403
  rb_define_method(classMemory, "put_bytes", memory_put_bytes, -1);
404
+ rb_define_method(classMemory, "get_array_of_string", memory_get_array_of_string, -1);
403
405
 
404
406
  rb_define_method(classMemory, "clear", memory_clear, 0);
405
407
  rb_define_method(classMemory, "total", memory_size, 0);
406
408
 
407
- to_ptr = rb_intern("to_ptr");
409
+ id_to_ptr = rb_intern("to_ptr");
410
+ id_call = rb_intern("call");
408
411
  }
409
412
 
@@ -5,6 +5,8 @@
5
5
  #include <sys/types.h>
6
6
  #include <stdint.h>
7
7
 
8
+ #include "compat.h"
9
+
8
10
  #ifdef __cplusplus
9
11
  extern "C" {
10
12
  #endif
@@ -47,14 +49,16 @@ checkBounds(AbstractMemory* mem, long off, long len)
47
49
  }
48
50
  }
49
51
 
50
- #define MEMORY(obj) rb_FFI_AbstractMemory_cast((obj), rb_FFI_AbstractMemory_class)
52
+ #define MEMORY(obj) rbffi_AbstractMemory_Cast((obj), rbffi_AbstractMemoryClass)
51
53
  #define MEMORY_PTR(obj) MEMORY((obj))->address
52
54
  #define MEMORY_LEN(obj) MEMORY((obj))->size
53
55
 
54
- extern AbstractMemory* rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass);
56
+ extern void rbffi_AbstractMemory_Init(VALUE ffiModule);
57
+
58
+ extern AbstractMemory* rbffi_AbstractMemory_Cast(VALUE obj, VALUE klass);
55
59
 
56
- extern VALUE rb_FFI_AbstractMemory_class;
57
- extern MemoryOps rb_FFI_AbstractMemory_ops;
60
+ extern VALUE rbffi_AbstractMemoryClass;
61
+ extern MemoryOps rbffi_AbstractMemoryOps;
58
62
 
59
63
  #ifdef __cplusplus
60
64
  }