ffi 0.3.0 → 0.3.1
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.
- data/Rakefile +11 -2
- data/ext/ffi_c/AbstractMemory.c +103 -23
- data/ext/ffi_c/AbstractMemory.h +27 -1
- data/ext/ffi_c/AutoPointer.c +13 -15
- data/ext/ffi_c/Buffer.c +46 -29
- data/ext/ffi_c/Callback.c +58 -39
- data/ext/ffi_c/Invoker.c +6 -2
- data/ext/ffi_c/MemoryPointer.c +4 -1
- data/ext/ffi_c/NativeLibrary.c +5 -8
- data/ext/ffi_c/NullPointer.c +35 -0
- data/ext/ffi_c/Pointer.c +21 -15
- data/ext/ffi_c/Struct.c +145 -219
- metadata +2 -2
data/Rakefile
CHANGED
@@ -31,9 +31,8 @@ PROJ.name = 'ffi'
|
|
31
31
|
PROJ.authors = 'Wayne Meissner'
|
32
32
|
PROJ.email = 'wmeissner@gmail.com'
|
33
33
|
PROJ.url = 'http://kenai.com/projects/ruby-ffi'
|
34
|
-
PROJ.version = '0.3.
|
34
|
+
PROJ.version = '0.3.1'
|
35
35
|
PROJ.rubyforge.name = 'ffi'
|
36
|
-
|
37
36
|
PROJ.readme_file = 'README.rdoc'
|
38
37
|
|
39
38
|
# Annoucement
|
@@ -52,6 +51,13 @@ PROJ.gem.extensions = %w(ext/ffi_c/extconf.rb gen/Rakefile)
|
|
52
51
|
PROJ.rdoc.exclude << '^ext\/'
|
53
52
|
PROJ.rdoc.opts << '-x' << 'ext'
|
54
53
|
|
54
|
+
# Ruby
|
55
|
+
PROJ.ruby_opts = []
|
56
|
+
PROJ.ruby_opts << '-I' << "\"#{BUILD_DIR}\"" unless RUBY_PLATFORM == "java"
|
57
|
+
|
58
|
+
#RSpec
|
59
|
+
PROJ.spec.opts << '--color' << '-fs'
|
60
|
+
|
55
61
|
TEST_DEPS = [ LIBTEST ]
|
56
62
|
if RUBY_PLATFORM == "java"
|
57
63
|
desc "Run all specs"
|
@@ -121,3 +127,6 @@ namespace :bench do
|
|
121
127
|
end
|
122
128
|
end
|
123
129
|
end
|
130
|
+
|
131
|
+
task 'spec:run' => TEST_DEPS
|
132
|
+
task 'spec:specdoc' => TEST_DEPS
|
data/ext/ffi_c/AbstractMemory.c
CHANGED
@@ -9,41 +9,60 @@
|
|
9
9
|
#include "Pointer.h"
|
10
10
|
#include "Callback.h"
|
11
11
|
|
12
|
-
static VALUE memory_put_float32(VALUE self, VALUE offset, VALUE value);
|
13
|
-
static VALUE memory_get_float32(VALUE self, VALUE offset);
|
14
|
-
static VALUE memory_put_float64(VALUE self, VALUE offset, VALUE value);
|
15
|
-
static VALUE memory_get_float64(VALUE self, VALUE offset);
|
16
|
-
static VALUE memory_put_pointer(VALUE self, VALUE offset, VALUE value);
|
17
|
-
static VALUE memory_get_pointer(VALUE self, VALUE offset);
|
18
12
|
|
19
13
|
static inline char* memory_address(VALUE self);
|
20
14
|
VALUE rb_FFI_AbstractMemory_class = Qnil;
|
21
15
|
static VALUE classMemory = Qnil;
|
22
16
|
static ID to_ptr = 0;
|
23
17
|
|
18
|
+
static VALUE
|
19
|
+
memory_allocate(VALUE klass)
|
20
|
+
{
|
21
|
+
AbstractMemory* memory;
|
22
|
+
VALUE obj;
|
23
|
+
obj = Data_Make_Struct(klass, AbstractMemory, NULL, -1, memory);
|
24
|
+
memory->ops = &rb_FFI_AbstractMemory_ops;
|
25
|
+
|
26
|
+
return obj;
|
27
|
+
}
|
28
|
+
|
24
29
|
#define NUM_OP(name, type, toNative, fromNative) \
|
25
|
-
static
|
26
|
-
static
|
27
|
-
|
30
|
+
static void memory_op_put_##name(AbstractMemory* memory, long off, VALUE value); \
|
31
|
+
static void \
|
32
|
+
memory_op_put_##name(AbstractMemory* memory, long off, VALUE value) \
|
28
33
|
{ \
|
29
|
-
long off = NUM2LONG(offset); \
|
30
|
-
AbstractMemory* memory = MEMORY(self); \
|
31
34
|
type tmp = (type) toNative(value); \
|
32
35
|
checkBounds(memory, off, sizeof(type)); \
|
33
36
|
memcpy(memory->address + off, &tmp, sizeof(tmp)); \
|
37
|
+
} \
|
38
|
+
static VALUE memory_put_##name(VALUE self, VALUE offset, VALUE value); \
|
39
|
+
static VALUE \
|
40
|
+
memory_put_##name(VALUE self, VALUE offset, VALUE value) \
|
41
|
+
{ \
|
42
|
+
AbstractMemory* memory; \
|
43
|
+
Data_Get_Struct(self, AbstractMemory, memory); \
|
44
|
+
memory_op_put_##name(memory, NUM2LONG(offset), value); \
|
34
45
|
return self; \
|
35
46
|
} \
|
36
|
-
static VALUE
|
47
|
+
static VALUE memory_op_get_##name(AbstractMemory* memory, long off); \
|
37
48
|
static VALUE \
|
38
|
-
|
49
|
+
memory_op_get_##name(AbstractMemory* memory, long off) \
|
39
50
|
{ \
|
40
|
-
long off = NUM2LONG(offset); \
|
41
|
-
AbstractMemory* memory = MEMORY(self); \
|
42
51
|
type tmp; \
|
43
52
|
checkBounds(memory, off, sizeof(type)); \
|
44
53
|
memcpy(&tmp, memory->address + off, sizeof(tmp)); \
|
45
54
|
return fromNative(tmp); \
|
46
55
|
} \
|
56
|
+
static VALUE memory_get_##name(VALUE self, VALUE offset); \
|
57
|
+
static VALUE \
|
58
|
+
memory_get_##name(VALUE self, VALUE offset) \
|
59
|
+
{ \
|
60
|
+
AbstractMemory* memory; \
|
61
|
+
Data_Get_Struct(self, AbstractMemory, memory); \
|
62
|
+
return memory_op_get_##name(memory, NUM2LONG(offset)); \
|
63
|
+
} \
|
64
|
+
static MemoryOp memory_op_##name = { memory_op_get_##name, memory_op_put_##name }; \
|
65
|
+
\
|
47
66
|
static VALUE memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary); \
|
48
67
|
static VALUE \
|
49
68
|
memory_put_array_of_##name(VALUE self, VALUE offset, VALUE ary) \
|
@@ -88,11 +107,9 @@ NUM_OP(uint64, uint64_t, NUM2ULL, ULL2NUM);
|
|
88
107
|
NUM_OP(float32, float, NUM2DBL, rb_float_new);
|
89
108
|
NUM_OP(float64, double, NUM2DBL, rb_float_new);
|
90
109
|
|
91
|
-
static
|
92
|
-
|
110
|
+
static void
|
111
|
+
memory_op_put_pointer(AbstractMemory* memory, long off, VALUE value)
|
93
112
|
{
|
94
|
-
AbstractMemory* memory = MEMORY(self);
|
95
|
-
long off = NUM2LONG(offset);
|
96
113
|
const int type = TYPE(value);
|
97
114
|
checkBounds(memory, off, sizeof(void *));
|
98
115
|
|
@@ -115,20 +132,39 @@ memory_put_pointer(VALUE self, VALUE offset, VALUE value)
|
|
115
132
|
} else {
|
116
133
|
rb_raise(rb_eArgError, "value is not a pointer");
|
117
134
|
}
|
118
|
-
return self;
|
119
135
|
}
|
120
136
|
|
121
137
|
static VALUE
|
122
|
-
|
138
|
+
memory_op_get_pointer(AbstractMemory* memory, long off)
|
123
139
|
{
|
124
|
-
AbstractMemory* memory = MEMORY(self);
|
125
|
-
long off = NUM2LONG(offset);
|
126
140
|
void* tmp;
|
141
|
+
|
127
142
|
checkBounds(memory, off, sizeof(tmp));
|
128
143
|
memcpy(&tmp, memory->address + off, sizeof(tmp));
|
129
144
|
return rb_FFI_Pointer_new(tmp);
|
130
145
|
}
|
131
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
|
+
}
|
167
|
+
|
132
168
|
static VALUE
|
133
169
|
memory_put_callback(VALUE self, VALUE offset, VALUE proc, VALUE cbInfo)
|
134
170
|
{
|
@@ -184,8 +220,10 @@ memory_put_string(VALUE self, VALUE offset, VALUE str)
|
|
184
220
|
AbstractMemory* ptr = MEMORY(self);
|
185
221
|
long off, len;
|
186
222
|
|
223
|
+
Check_Type(str, T_STRING);
|
187
224
|
off = NUM2LONG(offset);
|
188
225
|
len = RSTRING_LEN(str);
|
226
|
+
|
189
227
|
checkBounds(ptr, off, len);
|
190
228
|
if (rb_safe_level() >= 1 && OBJ_TAINTED(str)) {
|
191
229
|
rb_raise(rb_eSecurityError, "Writing unsafe string to memory");
|
@@ -215,6 +253,8 @@ memory_put_bytes(int argc, VALUE* argv, VALUE self)
|
|
215
253
|
long off, len, idx;
|
216
254
|
int nargs = rb_scan_args(argc, argv, "22", &offset, &str, &rbIndex, &rbLength);
|
217
255
|
|
256
|
+
Check_Type(str, T_STRING);
|
257
|
+
|
218
258
|
off = NUM2LONG(offset);
|
219
259
|
idx = nargs > 2 ? NUM2LONG(rbIndex) : 0;
|
220
260
|
if (idx < 0) {
|
@@ -249,11 +289,51 @@ rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass)
|
|
249
289
|
rb_raise(rb_eArgError, "Invalid Memory object");
|
250
290
|
}
|
251
291
|
|
292
|
+
static VALUE
|
293
|
+
memory_op_get_strptr(AbstractMemory* ptr, long offset)
|
294
|
+
{
|
295
|
+
void* tmp = NULL;
|
296
|
+
|
297
|
+
if (ptr != NULL && ptr->address != NULL) {
|
298
|
+
checkBounds(ptr, offset, sizeof(tmp));
|
299
|
+
memcpy(&tmp, ptr->address + offset, sizeof(tmp));
|
300
|
+
}
|
301
|
+
|
302
|
+
return tmp != NULL ? rb_tainted_str_new2(tmp) : Qnil;
|
303
|
+
}
|
304
|
+
|
305
|
+
static void
|
306
|
+
memory_op_put_strptr(AbstractMemory* ptr, long offset, VALUE value)
|
307
|
+
{
|
308
|
+
rb_raise(rb_eArgError, "Cannot set :string fields");
|
309
|
+
}
|
310
|
+
|
311
|
+
static MemoryOp memory_op_strptr = { memory_op_get_strptr, memory_op_put_strptr };
|
312
|
+
|
313
|
+
static MemoryOp memory_op_pointer = { memory_op_get_pointer, memory_op_put_pointer };
|
314
|
+
|
315
|
+
MemoryOps rb_FFI_AbstractMemory_ops = {
|
316
|
+
.int8 = &memory_op_int8,
|
317
|
+
.uint8 = &memory_op_uint8,
|
318
|
+
.int16 = &memory_op_int16,
|
319
|
+
.uint16 = &memory_op_uint16,
|
320
|
+
.int32 = &memory_op_int32,
|
321
|
+
.uint32 = &memory_op_uint32,
|
322
|
+
.int64 = &memory_op_int64,
|
323
|
+
.uint64 = &memory_op_uint64,
|
324
|
+
.float32 = &memory_op_float32,
|
325
|
+
.float64 = &memory_op_float64,
|
326
|
+
.pointer = &memory_op_pointer,
|
327
|
+
.strptr = &memory_op_strptr,
|
328
|
+
};
|
329
|
+
|
252
330
|
void
|
253
331
|
rb_FFI_AbstractMemory_Init()
|
254
332
|
{
|
255
333
|
VALUE moduleFFI = rb_define_module("FFI");
|
256
334
|
rb_FFI_AbstractMemory_class = classMemory = rb_define_class_under(moduleFFI, "AbstractMemory", rb_cObject);
|
335
|
+
|
336
|
+
rb_define_alloc_func(classMemory, memory_allocate);
|
257
337
|
#undef INT
|
258
338
|
#define INT(type) \
|
259
339
|
rb_define_method(classMemory, "put_" #type, memory_put_##type, 2); \
|
data/ext/ffi_c/AbstractMemory.h
CHANGED
@@ -9,10 +9,34 @@
|
|
9
9
|
extern "C" {
|
10
10
|
#endif
|
11
11
|
|
12
|
+
typedef struct AbstractMemory_ AbstractMemory;
|
13
|
+
|
14
|
+
typedef struct {
|
15
|
+
VALUE (*get)(AbstractMemory* ptr, long offset);
|
16
|
+
void (*put)(AbstractMemory* ptr, long offset, VALUE value);
|
17
|
+
} MemoryOp;
|
18
|
+
|
12
19
|
typedef struct {
|
20
|
+
MemoryOp* int8;
|
21
|
+
MemoryOp* uint8;
|
22
|
+
MemoryOp* int16;
|
23
|
+
MemoryOp* uint16;
|
24
|
+
MemoryOp* int32;
|
25
|
+
MemoryOp* uint32;
|
26
|
+
MemoryOp* int64;
|
27
|
+
MemoryOp* uint64;
|
28
|
+
MemoryOp* float32;
|
29
|
+
MemoryOp* float64;
|
30
|
+
MemoryOp* pointer;
|
31
|
+
MemoryOp* strptr;
|
32
|
+
} MemoryOps;
|
33
|
+
|
34
|
+
struct AbstractMemory_ {
|
13
35
|
char* address; // Use char* instead of void* to ensure adding to it works correctly
|
14
36
|
long size;
|
15
|
-
|
37
|
+
MemoryOps* ops;
|
38
|
+
};
|
39
|
+
|
16
40
|
|
17
41
|
static inline void
|
18
42
|
checkBounds(AbstractMemory* mem, long off, long len)
|
@@ -30,6 +54,8 @@ checkBounds(AbstractMemory* mem, long off, long len)
|
|
30
54
|
extern AbstractMemory* rb_FFI_AbstractMemory_cast(VALUE obj, VALUE klass);
|
31
55
|
|
32
56
|
extern VALUE rb_FFI_AbstractMemory_class;
|
57
|
+
extern MemoryOps rb_FFI_AbstractMemory_ops;
|
58
|
+
|
33
59
|
#ifdef __cplusplus
|
34
60
|
}
|
35
61
|
#endif
|
data/ext/ffi_c/AutoPointer.c
CHANGED
@@ -13,17 +13,20 @@ typedef struct AutoPointer {
|
|
13
13
|
VALUE parent;
|
14
14
|
} AutoPointer;
|
15
15
|
|
16
|
-
VALUE rb_FFI_AutoPointer_class;
|
17
|
-
static VALUE classAutoPointer = Qnil;
|
18
16
|
static void autoptr_mark(AutoPointer* ptr);
|
19
|
-
static
|
17
|
+
static VALUE autoptr_allocate(VALUE klass);
|
18
|
+
static VALUE autoptr_set_parent(VALUE self, VALUE parent);
|
19
|
+
|
20
|
+
VALUE rb_FFI_AutoPointer_class = Qnil;
|
20
21
|
|
21
22
|
static VALUE
|
22
23
|
autoptr_allocate(VALUE klass)
|
23
24
|
{
|
24
25
|
AutoPointer* p;
|
25
|
-
VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark,
|
26
|
+
VALUE obj = Data_Make_Struct(klass, AutoPointer, autoptr_mark, -1, p);
|
26
27
|
p->parent = Qnil;
|
28
|
+
p->memory.ops = &rb_FFI_AbstractMemory_ops;
|
29
|
+
|
27
30
|
return obj;
|
28
31
|
}
|
29
32
|
|
@@ -43,21 +46,16 @@ autoptr_set_parent(VALUE self, VALUE parent)
|
|
43
46
|
static void
|
44
47
|
autoptr_mark(AutoPointer* ptr)
|
45
48
|
{
|
46
|
-
|
47
|
-
rb_gc_mark(ptr->parent);
|
48
|
-
}
|
49
|
-
}
|
50
|
-
static void
|
51
|
-
autoptr_free(AutoPointer* ptr)
|
52
|
-
{
|
53
|
-
xfree(ptr);
|
49
|
+
rb_gc_mark(ptr->parent);
|
54
50
|
}
|
55
51
|
|
56
52
|
void
|
57
53
|
rb_FFI_AutoPointer_Init()
|
58
54
|
{
|
59
55
|
VALUE moduleFFI = rb_define_module("FFI");
|
60
|
-
rb_FFI_AutoPointer_class =
|
61
|
-
|
62
|
-
|
56
|
+
rb_FFI_AutoPointer_class = rb_define_class_under(moduleFFI, "AutoPointer", rb_FFI_Pointer_class);
|
57
|
+
rb_global_variable(&rb_FFI_AutoPointer_class);
|
58
|
+
|
59
|
+
rb_define_alloc_func(rb_FFI_AutoPointer_class, autoptr_allocate);
|
60
|
+
rb_define_protected_method(rb_FFI_AutoPointer_class, "parent=", autoptr_set_parent, 1);
|
63
61
|
}
|
data/ext/ffi_c/Buffer.c
CHANGED
@@ -25,7 +25,24 @@ static VALUE
|
|
25
25
|
buffer_allocate(VALUE klass)
|
26
26
|
{
|
27
27
|
Buffer* buffer;
|
28
|
-
|
28
|
+
VALUE obj;
|
29
|
+
|
30
|
+
obj = Data_Make_Struct(klass, Buffer, NULL, buffer_release, buffer);
|
31
|
+
buffer->parent = Qnil;
|
32
|
+
buffer->memory.ops = &rb_FFI_AbstractMemory_ops;
|
33
|
+
|
34
|
+
return obj;
|
35
|
+
}
|
36
|
+
|
37
|
+
static void
|
38
|
+
buffer_release(Buffer* ptr)
|
39
|
+
{
|
40
|
+
if (ptr->storage != NULL) {
|
41
|
+
free(ptr->storage);
|
42
|
+
ptr->storage = NULL;
|
43
|
+
}
|
44
|
+
|
45
|
+
xfree(ptr);
|
29
46
|
}
|
30
47
|
|
31
48
|
static VALUE
|
@@ -34,27 +51,30 @@ buffer_initialize(int argc, VALUE* argv, VALUE self)
|
|
34
51
|
VALUE size = Qnil, count = Qnil, clear = Qnil;
|
35
52
|
Buffer* p;
|
36
53
|
unsigned long msize;
|
37
|
-
void* memory;
|
38
54
|
int nargs;
|
39
|
-
|
55
|
+
|
40
56
|
nargs = rb_scan_args(argc, argv, "12", &size, &count, &clear);
|
41
57
|
msize = rb_FFI_type_size(size) * (nargs > 1 ? NUM2LONG(count) : 1);
|
42
|
-
|
43
|
-
if (memory == NULL) {
|
44
|
-
rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", msize);
|
45
|
-
}
|
58
|
+
|
46
59
|
Data_Get_Struct(self, Buffer, p);
|
47
|
-
p->storage = memory;
|
48
60
|
p->memory.size = msize;
|
61
|
+
|
62
|
+
p->storage = malloc(msize + 7);
|
63
|
+
if (p->storage == NULL) {
|
64
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory size=%lu bytes", msize);
|
65
|
+
}
|
66
|
+
|
49
67
|
/* ensure the memory is aligned on at least a 8 byte boundary */
|
50
|
-
p->memory.address = (void *) (((uintptr_t)
|
51
|
-
|
68
|
+
p->memory.address = (void *) (((uintptr_t) p->storage + 0x7) & (uintptr_t) ~0x7UL);
|
69
|
+
|
52
70
|
if (nargs > 2 && RTEST(clear) && p->memory.size > 0) {
|
53
71
|
memset(p->memory.address, 0, p->memory.size);
|
54
72
|
}
|
73
|
+
|
55
74
|
if (rb_block_given_p()) {
|
56
|
-
return
|
75
|
+
return rb_ensure(rb_yield, self, buffer_free, self);
|
57
76
|
}
|
77
|
+
|
58
78
|
return self;
|
59
79
|
}
|
60
80
|
|
@@ -73,10 +93,13 @@ buffer_plus(VALUE self, VALUE offset)
|
|
73
93
|
long off = NUM2LONG(offset);
|
74
94
|
|
75
95
|
checkBounds(&ptr->memory, off, 1);
|
76
|
-
|
77
|
-
|
96
|
+
|
97
|
+
retval = Data_Make_Struct(classBuffer, Buffer, buffer_mark, -1, p);
|
98
|
+
p->memory.address = ptr->memory.address + off;
|
78
99
|
p->memory.size = ptr->memory.size - off;
|
100
|
+
p->memory.ops = &rb_FFI_AbstractMemory_ops;
|
79
101
|
p->parent = self;
|
102
|
+
|
80
103
|
return retval;
|
81
104
|
}
|
82
105
|
|
@@ -84,7 +107,9 @@ static VALUE
|
|
84
107
|
buffer_inspect(VALUE self)
|
85
108
|
{
|
86
109
|
char tmp[100];
|
110
|
+
|
87
111
|
snprintf(tmp, sizeof(tmp), "#<Buffer size=%ld>", BUFFER(self)->memory.size);
|
112
|
+
|
88
113
|
return rb_str_new2(tmp);
|
89
114
|
}
|
90
115
|
|
@@ -92,30 +117,21 @@ buffer_inspect(VALUE self)
|
|
92
117
|
static VALUE
|
93
118
|
buffer_free(VALUE self)
|
94
119
|
{
|
95
|
-
Buffer* ptr
|
96
|
-
if (ptr->parent == Qnil && ptr->storage != NULL) {
|
97
|
-
free(ptr->storage);
|
98
|
-
ptr->storage = NULL;
|
99
|
-
}
|
100
|
-
return self;
|
101
|
-
}
|
120
|
+
Buffer* ptr;
|
102
121
|
|
103
|
-
|
104
|
-
|
105
|
-
{
|
106
|
-
if (ptr->parent == Qnil && ptr->storage != NULL) {
|
122
|
+
Data_Get_Struct(self, Buffer, ptr);
|
123
|
+
if (ptr->storage != NULL) {
|
107
124
|
free(ptr->storage);
|
108
125
|
ptr->storage = NULL;
|
109
126
|
}
|
110
|
-
|
127
|
+
|
128
|
+
return self;
|
111
129
|
}
|
112
130
|
|
113
131
|
static void
|
114
132
|
buffer_mark(Buffer* ptr)
|
115
133
|
{
|
116
|
-
|
117
|
-
rb_gc_mark(ptr->parent);
|
118
|
-
}
|
134
|
+
rb_gc_mark(ptr->parent);
|
119
135
|
}
|
120
136
|
|
121
137
|
void
|
@@ -123,6 +139,8 @@ rb_FFI_Buffer_Init()
|
|
123
139
|
{
|
124
140
|
VALUE moduleFFI = rb_define_module("FFI");
|
125
141
|
classBuffer = rb_define_class_under(moduleFFI, "Buffer", rb_FFI_AbstractMemory_class);
|
142
|
+
|
143
|
+
rb_global_variable(&classBuffer);
|
126
144
|
rb_define_alloc_func(classBuffer, buffer_allocate);
|
127
145
|
|
128
146
|
rb_define_singleton_method(classBuffer, "alloc_inout", buffer_alloc_inout, -1);
|
@@ -133,4 +151,3 @@ rb_FFI_Buffer_Init()
|
|
133
151
|
rb_define_method(classBuffer, "inspect", buffer_inspect, 0);
|
134
152
|
rb_define_method(classBuffer, "+", buffer_plus, 1);
|
135
153
|
}
|
136
|
-
|