fiddle 1.0.0.beta1
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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +13 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ext/fiddle/closure.c +345 -0
- data/ext/fiddle/closure.h +8 -0
- data/ext/fiddle/conversions.c +141 -0
- data/ext/fiddle/conversions.h +44 -0
- data/ext/fiddle/extconf.rb +183 -0
- data/ext/fiddle/extlibs +2 -0
- data/ext/fiddle/fiddle.c +454 -0
- data/ext/fiddle/fiddle.h +138 -0
- data/ext/fiddle/function.c +315 -0
- data/ext/fiddle/function.h +8 -0
- data/ext/fiddle/handle.c +479 -0
- data/ext/fiddle/pointer.c +721 -0
- data/ext/fiddle/win32/fficonfig.h +29 -0
- data/ext/fiddle/win32/libffi-3.2.1-mswin.patch +191 -0
- data/ext/fiddle/win32/libffi-config.rb +48 -0
- data/ext/fiddle/win32/libffi.mk.tmpl +96 -0
- data/fiddle.gemspec +23 -0
- data/lib/fiddle.rb +56 -0
- data/lib/fiddle/closure.rb +49 -0
- data/lib/fiddle/cparser.rb +194 -0
- data/lib/fiddle/function.rb +18 -0
- data/lib/fiddle/import.rb +318 -0
- data/lib/fiddle/pack.rb +129 -0
- data/lib/fiddle/struct.rb +244 -0
- data/lib/fiddle/types.rb +72 -0
- data/lib/fiddle/value.rb +113 -0
- metadata +136 -0
@@ -0,0 +1,721 @@
|
|
1
|
+
/* -*- C -*-
|
2
|
+
* $Id$
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <ruby/ruby.h>
|
6
|
+
#include <ruby/io.h>
|
7
|
+
#include <ctype.h>
|
8
|
+
#include <fiddle.h>
|
9
|
+
|
10
|
+
#ifdef PRIsVALUE
|
11
|
+
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
12
|
+
# define RB_OBJ_STRING(obj) (obj)
|
13
|
+
#else
|
14
|
+
# define PRIsVALUE "s"
|
15
|
+
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
16
|
+
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
17
|
+
#endif
|
18
|
+
|
19
|
+
VALUE rb_cPointer;
|
20
|
+
|
21
|
+
typedef void (*freefunc_t)(void*);
|
22
|
+
|
23
|
+
struct ptr_data {
|
24
|
+
void *ptr;
|
25
|
+
long size;
|
26
|
+
freefunc_t free;
|
27
|
+
VALUE wrap[2];
|
28
|
+
};
|
29
|
+
|
30
|
+
#define RPTR_DATA(obj) ((struct ptr_data *)(DATA_PTR(obj)))
|
31
|
+
|
32
|
+
static inline freefunc_t
|
33
|
+
get_freefunc(VALUE func, volatile VALUE *wrap)
|
34
|
+
{
|
35
|
+
VALUE addrnum;
|
36
|
+
if (NIL_P(func)) {
|
37
|
+
*wrap = 0;
|
38
|
+
return NULL;
|
39
|
+
}
|
40
|
+
addrnum = rb_Integer(func);
|
41
|
+
*wrap = (addrnum != func) ? func : 0;
|
42
|
+
return (freefunc_t)(VALUE)NUM2PTR(addrnum);
|
43
|
+
}
|
44
|
+
|
45
|
+
static ID id_to_ptr;
|
46
|
+
|
47
|
+
static void
|
48
|
+
fiddle_ptr_mark(void *ptr)
|
49
|
+
{
|
50
|
+
struct ptr_data *data = ptr;
|
51
|
+
if (data->wrap[0]) {
|
52
|
+
rb_gc_mark(data->wrap[0]);
|
53
|
+
}
|
54
|
+
if (data->wrap[1]) {
|
55
|
+
rb_gc_mark(data->wrap[1]);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
static void
|
60
|
+
fiddle_ptr_free(void *ptr)
|
61
|
+
{
|
62
|
+
struct ptr_data *data = ptr;
|
63
|
+
if (data->ptr) {
|
64
|
+
if (data->free) {
|
65
|
+
(*(data->free))(data->ptr);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
xfree(ptr);
|
69
|
+
}
|
70
|
+
|
71
|
+
static size_t
|
72
|
+
fiddle_ptr_memsize(const void *ptr)
|
73
|
+
{
|
74
|
+
const struct ptr_data *data = ptr;
|
75
|
+
return sizeof(*data) + data->size;
|
76
|
+
}
|
77
|
+
|
78
|
+
static const rb_data_type_t fiddle_ptr_data_type = {
|
79
|
+
"fiddle/pointer",
|
80
|
+
{fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
|
81
|
+
};
|
82
|
+
|
83
|
+
static VALUE
|
84
|
+
rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
|
85
|
+
{
|
86
|
+
struct ptr_data *data;
|
87
|
+
VALUE val;
|
88
|
+
|
89
|
+
val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
|
90
|
+
data->ptr = ptr;
|
91
|
+
data->free = func;
|
92
|
+
data->size = size;
|
93
|
+
OBJ_TAINT(val);
|
94
|
+
|
95
|
+
return val;
|
96
|
+
}
|
97
|
+
|
98
|
+
static VALUE
|
99
|
+
rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
|
100
|
+
{
|
101
|
+
return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func);
|
102
|
+
}
|
103
|
+
|
104
|
+
static VALUE
|
105
|
+
rb_fiddle_ptr_malloc(long size, freefunc_t func)
|
106
|
+
{
|
107
|
+
void *ptr;
|
108
|
+
|
109
|
+
ptr = ruby_xmalloc((size_t)size);
|
110
|
+
memset(ptr,0,(size_t)size);
|
111
|
+
return rb_fiddle_ptr_new(ptr, size, func);
|
112
|
+
}
|
113
|
+
|
114
|
+
static void *
|
115
|
+
rb_fiddle_ptr2cptr(VALUE val)
|
116
|
+
{
|
117
|
+
struct ptr_data *data;
|
118
|
+
void *ptr;
|
119
|
+
|
120
|
+
if (rb_obj_is_kind_of(val, rb_cPointer)) {
|
121
|
+
TypedData_Get_Struct(val, struct ptr_data, &fiddle_ptr_data_type, data);
|
122
|
+
ptr = data->ptr;
|
123
|
+
}
|
124
|
+
else if (val == Qnil) {
|
125
|
+
ptr = NULL;
|
126
|
+
}
|
127
|
+
else{
|
128
|
+
rb_raise(rb_eTypeError, "Fiddle::Pointer was expected");
|
129
|
+
}
|
130
|
+
|
131
|
+
return ptr;
|
132
|
+
}
|
133
|
+
|
134
|
+
static VALUE
|
135
|
+
rb_fiddle_ptr_s_allocate(VALUE klass)
|
136
|
+
{
|
137
|
+
VALUE obj;
|
138
|
+
struct ptr_data *data;
|
139
|
+
|
140
|
+
obj = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
|
141
|
+
data->ptr = 0;
|
142
|
+
data->size = 0;
|
143
|
+
data->free = 0;
|
144
|
+
|
145
|
+
return obj;
|
146
|
+
}
|
147
|
+
|
148
|
+
/*
|
149
|
+
* call-seq:
|
150
|
+
* Fiddle::Pointer.new(address) => fiddle_cptr
|
151
|
+
* new(address, size) => fiddle_cptr
|
152
|
+
* new(address, size, freefunc) => fiddle_cptr
|
153
|
+
*
|
154
|
+
* Create a new pointer to +address+ with an optional +size+ and +freefunc+.
|
155
|
+
*
|
156
|
+
* +freefunc+ will be called when the instance is garbage collected.
|
157
|
+
*/
|
158
|
+
static VALUE
|
159
|
+
rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
|
160
|
+
{
|
161
|
+
VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
|
162
|
+
struct ptr_data *data;
|
163
|
+
void *p = NULL;
|
164
|
+
freefunc_t f = NULL;
|
165
|
+
long s = 0;
|
166
|
+
|
167
|
+
if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
|
168
|
+
VALUE addrnum = rb_Integer(ptr);
|
169
|
+
if (addrnum != ptr) wrap = ptr;
|
170
|
+
p = NUM2PTR(addrnum);
|
171
|
+
}
|
172
|
+
if (argc >= 2) {
|
173
|
+
s = NUM2LONG(size);
|
174
|
+
}
|
175
|
+
if (argc >= 3) {
|
176
|
+
f = get_freefunc(sym, &funcwrap);
|
177
|
+
}
|
178
|
+
|
179
|
+
if (p) {
|
180
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
181
|
+
if (data->ptr && data->free) {
|
182
|
+
/* Free previous memory. Use of inappropriate initialize may cause SEGV. */
|
183
|
+
(*(data->free))(data->ptr);
|
184
|
+
}
|
185
|
+
data->wrap[0] = wrap;
|
186
|
+
data->wrap[1] = funcwrap;
|
187
|
+
data->ptr = p;
|
188
|
+
data->size = s;
|
189
|
+
data->free = f;
|
190
|
+
}
|
191
|
+
|
192
|
+
return Qnil;
|
193
|
+
}
|
194
|
+
|
195
|
+
/*
|
196
|
+
* call-seq:
|
197
|
+
*
|
198
|
+
* Fiddle::Pointer.malloc(size, freefunc = nil) => fiddle pointer instance
|
199
|
+
*
|
200
|
+
* Allocate +size+ bytes of memory and associate it with an optional
|
201
|
+
* +freefunc+ that will be called when the pointer is garbage collected.
|
202
|
+
*
|
203
|
+
* +freefunc+ must be an address pointing to a function or an instance of
|
204
|
+
* Fiddle::Function
|
205
|
+
*/
|
206
|
+
static VALUE
|
207
|
+
rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
|
208
|
+
{
|
209
|
+
VALUE size, sym, obj, wrap = 0;
|
210
|
+
long s;
|
211
|
+
freefunc_t f;
|
212
|
+
|
213
|
+
switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
|
214
|
+
case 1:
|
215
|
+
s = NUM2LONG(size);
|
216
|
+
f = NULL;
|
217
|
+
break;
|
218
|
+
case 2:
|
219
|
+
s = NUM2LONG(size);
|
220
|
+
f = get_freefunc(sym, &wrap);
|
221
|
+
break;
|
222
|
+
default:
|
223
|
+
rb_bug("rb_fiddle_ptr_s_malloc");
|
224
|
+
}
|
225
|
+
|
226
|
+
obj = rb_fiddle_ptr_malloc(s,f);
|
227
|
+
if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
|
228
|
+
|
229
|
+
return obj;
|
230
|
+
}
|
231
|
+
|
232
|
+
/*
|
233
|
+
* call-seq: to_i
|
234
|
+
*
|
235
|
+
* Returns the integer memory location of this pointer.
|
236
|
+
*/
|
237
|
+
static VALUE
|
238
|
+
rb_fiddle_ptr_to_i(VALUE self)
|
239
|
+
{
|
240
|
+
struct ptr_data *data;
|
241
|
+
|
242
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
243
|
+
return PTR2NUM(data->ptr);
|
244
|
+
}
|
245
|
+
|
246
|
+
/*
|
247
|
+
* call-seq: to_value
|
248
|
+
*
|
249
|
+
* Cast this pointer to a ruby object.
|
250
|
+
*/
|
251
|
+
static VALUE
|
252
|
+
rb_fiddle_ptr_to_value(VALUE self)
|
253
|
+
{
|
254
|
+
struct ptr_data *data;
|
255
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
256
|
+
return (VALUE)(data->ptr);
|
257
|
+
}
|
258
|
+
|
259
|
+
/*
|
260
|
+
* call-seq: ptr
|
261
|
+
*
|
262
|
+
* Returns a new Fiddle::Pointer instance that is a dereferenced pointer for
|
263
|
+
* this pointer.
|
264
|
+
*
|
265
|
+
* Analogous to the star operator in C.
|
266
|
+
*/
|
267
|
+
static VALUE
|
268
|
+
rb_fiddle_ptr_ptr(VALUE self)
|
269
|
+
{
|
270
|
+
struct ptr_data *data;
|
271
|
+
|
272
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
273
|
+
return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
|
274
|
+
}
|
275
|
+
|
276
|
+
/*
|
277
|
+
* call-seq: ref
|
278
|
+
*
|
279
|
+
* Returns a new Fiddle::Pointer instance that is a reference pointer for this
|
280
|
+
* pointer.
|
281
|
+
*
|
282
|
+
* Analogous to the ampersand operator in C.
|
283
|
+
*/
|
284
|
+
static VALUE
|
285
|
+
rb_fiddle_ptr_ref(VALUE self)
|
286
|
+
{
|
287
|
+
struct ptr_data *data;
|
288
|
+
|
289
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
290
|
+
return rb_fiddle_ptr_new(&(data->ptr),0,0);
|
291
|
+
}
|
292
|
+
|
293
|
+
/*
|
294
|
+
* call-seq: null?
|
295
|
+
*
|
296
|
+
* Returns +true+ if this is a null pointer.
|
297
|
+
*/
|
298
|
+
static VALUE
|
299
|
+
rb_fiddle_ptr_null_p(VALUE self)
|
300
|
+
{
|
301
|
+
struct ptr_data *data;
|
302
|
+
|
303
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
304
|
+
return data->ptr ? Qfalse : Qtrue;
|
305
|
+
}
|
306
|
+
|
307
|
+
/*
|
308
|
+
* call-seq: free=(function)
|
309
|
+
*
|
310
|
+
* Set the free function for this pointer to +function+ in the given
|
311
|
+
* Fiddle::Function.
|
312
|
+
*/
|
313
|
+
static VALUE
|
314
|
+
rb_fiddle_ptr_free_set(VALUE self, VALUE val)
|
315
|
+
{
|
316
|
+
struct ptr_data *data;
|
317
|
+
|
318
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
319
|
+
data->free = get_freefunc(val, &data->wrap[1]);
|
320
|
+
|
321
|
+
return Qnil;
|
322
|
+
}
|
323
|
+
|
324
|
+
/*
|
325
|
+
* call-seq: free => Fiddle::Function
|
326
|
+
*
|
327
|
+
* Get the free function for this pointer.
|
328
|
+
*
|
329
|
+
* Returns a new instance of Fiddle::Function.
|
330
|
+
*
|
331
|
+
* See Fiddle::Function.new
|
332
|
+
*/
|
333
|
+
static VALUE
|
334
|
+
rb_fiddle_ptr_free_get(VALUE self)
|
335
|
+
{
|
336
|
+
struct ptr_data *pdata;
|
337
|
+
VALUE address;
|
338
|
+
VALUE arg_types;
|
339
|
+
VALUE ret_type;
|
340
|
+
|
341
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
|
342
|
+
|
343
|
+
if (!pdata->free)
|
344
|
+
return Qnil;
|
345
|
+
|
346
|
+
address = PTR2NUM(pdata->free);
|
347
|
+
ret_type = INT2NUM(TYPE_VOID);
|
348
|
+
arg_types = rb_ary_new();
|
349
|
+
rb_ary_push(arg_types, INT2NUM(TYPE_VOIDP));
|
350
|
+
|
351
|
+
return rb_fiddle_new_function(address, arg_types, ret_type);
|
352
|
+
}
|
353
|
+
|
354
|
+
/*
|
355
|
+
* call-seq:
|
356
|
+
*
|
357
|
+
* ptr.to_s => string
|
358
|
+
* ptr.to_s(len) => string
|
359
|
+
*
|
360
|
+
* Returns the pointer contents as a string.
|
361
|
+
*
|
362
|
+
* When called with no arguments, this method will return the contents until
|
363
|
+
* the first NULL byte.
|
364
|
+
*
|
365
|
+
* When called with +len+, a string of +len+ bytes will be returned.
|
366
|
+
*
|
367
|
+
* See to_str
|
368
|
+
*/
|
369
|
+
static VALUE
|
370
|
+
rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
|
371
|
+
{
|
372
|
+
struct ptr_data *data;
|
373
|
+
VALUE arg1, val;
|
374
|
+
int len;
|
375
|
+
|
376
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
377
|
+
switch (rb_scan_args(argc, argv, "01", &arg1)) {
|
378
|
+
case 0:
|
379
|
+
val = rb_tainted_str_new2((char*)(data->ptr));
|
380
|
+
break;
|
381
|
+
case 1:
|
382
|
+
len = NUM2INT(arg1);
|
383
|
+
val = rb_tainted_str_new((char*)(data->ptr), len);
|
384
|
+
break;
|
385
|
+
default:
|
386
|
+
rb_bug("rb_fiddle_ptr_to_s");
|
387
|
+
}
|
388
|
+
|
389
|
+
return val;
|
390
|
+
}
|
391
|
+
|
392
|
+
/*
|
393
|
+
* call-seq:
|
394
|
+
*
|
395
|
+
* ptr.to_str => string
|
396
|
+
* ptr.to_str(len) => string
|
397
|
+
*
|
398
|
+
* Returns the pointer contents as a string.
|
399
|
+
*
|
400
|
+
* When called with no arguments, this method will return the contents with the
|
401
|
+
* length of this pointer's +size+.
|
402
|
+
*
|
403
|
+
* When called with +len+, a string of +len+ bytes will be returned.
|
404
|
+
*
|
405
|
+
* See to_s
|
406
|
+
*/
|
407
|
+
static VALUE
|
408
|
+
rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
|
409
|
+
{
|
410
|
+
struct ptr_data *data;
|
411
|
+
VALUE arg1, val;
|
412
|
+
int len;
|
413
|
+
|
414
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
415
|
+
switch (rb_scan_args(argc, argv, "01", &arg1)) {
|
416
|
+
case 0:
|
417
|
+
val = rb_tainted_str_new((char*)(data->ptr),data->size);
|
418
|
+
break;
|
419
|
+
case 1:
|
420
|
+
len = NUM2INT(arg1);
|
421
|
+
val = rb_tainted_str_new((char*)(data->ptr), len);
|
422
|
+
break;
|
423
|
+
default:
|
424
|
+
rb_bug("rb_fiddle_ptr_to_str");
|
425
|
+
}
|
426
|
+
|
427
|
+
return val;
|
428
|
+
}
|
429
|
+
|
430
|
+
/*
|
431
|
+
* call-seq: inspect
|
432
|
+
*
|
433
|
+
* Returns a string formatted with an easily readable representation of the
|
434
|
+
* internal state of the pointer.
|
435
|
+
*/
|
436
|
+
static VALUE
|
437
|
+
rb_fiddle_ptr_inspect(VALUE self)
|
438
|
+
{
|
439
|
+
struct ptr_data *data;
|
440
|
+
|
441
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
442
|
+
return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
|
443
|
+
RB_OBJ_CLASSNAME(self), data, data->ptr, data->size, data->free);
|
444
|
+
}
|
445
|
+
|
446
|
+
/*
|
447
|
+
* call-seq:
|
448
|
+
* ptr == other => true or false
|
449
|
+
* ptr.eql?(other) => true or false
|
450
|
+
*
|
451
|
+
* Returns true if +other+ wraps the same pointer, otherwise returns
|
452
|
+
* false.
|
453
|
+
*/
|
454
|
+
static VALUE
|
455
|
+
rb_fiddle_ptr_eql(VALUE self, VALUE other)
|
456
|
+
{
|
457
|
+
void *ptr1, *ptr2;
|
458
|
+
|
459
|
+
if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;
|
460
|
+
|
461
|
+
ptr1 = rb_fiddle_ptr2cptr(self);
|
462
|
+
ptr2 = rb_fiddle_ptr2cptr(other);
|
463
|
+
|
464
|
+
return ptr1 == ptr2 ? Qtrue : Qfalse;
|
465
|
+
}
|
466
|
+
|
467
|
+
/*
|
468
|
+
* call-seq:
|
469
|
+
* ptr <=> other => -1, 0, 1, or nil
|
470
|
+
*
|
471
|
+
* Returns -1 if less than, 0 if equal to, 1 if greater than +other+.
|
472
|
+
*
|
473
|
+
* Returns nil if +ptr+ cannot be compared to +other+.
|
474
|
+
*/
|
475
|
+
static VALUE
|
476
|
+
rb_fiddle_ptr_cmp(VALUE self, VALUE other)
|
477
|
+
{
|
478
|
+
void *ptr1, *ptr2;
|
479
|
+
SIGNED_VALUE diff;
|
480
|
+
|
481
|
+
if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qnil;
|
482
|
+
|
483
|
+
ptr1 = rb_fiddle_ptr2cptr(self);
|
484
|
+
ptr2 = rb_fiddle_ptr2cptr(other);
|
485
|
+
diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
|
486
|
+
if (!diff) return INT2FIX(0);
|
487
|
+
return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
|
488
|
+
}
|
489
|
+
|
490
|
+
/*
|
491
|
+
* call-seq:
|
492
|
+
* ptr + n => new cptr
|
493
|
+
*
|
494
|
+
* Returns a new pointer instance that has been advanced +n+ bytes.
|
495
|
+
*/
|
496
|
+
static VALUE
|
497
|
+
rb_fiddle_ptr_plus(VALUE self, VALUE other)
|
498
|
+
{
|
499
|
+
void *ptr;
|
500
|
+
long num, size;
|
501
|
+
|
502
|
+
ptr = rb_fiddle_ptr2cptr(self);
|
503
|
+
size = RPTR_DATA(self)->size;
|
504
|
+
num = NUM2LONG(other);
|
505
|
+
return rb_fiddle_ptr_new((char *)ptr + num, size - num, 0);
|
506
|
+
}
|
507
|
+
|
508
|
+
/*
|
509
|
+
* call-seq:
|
510
|
+
* ptr - n => new cptr
|
511
|
+
*
|
512
|
+
* Returns a new pointer instance that has been moved back +n+ bytes.
|
513
|
+
*/
|
514
|
+
static VALUE
|
515
|
+
rb_fiddle_ptr_minus(VALUE self, VALUE other)
|
516
|
+
{
|
517
|
+
void *ptr;
|
518
|
+
long num, size;
|
519
|
+
|
520
|
+
ptr = rb_fiddle_ptr2cptr(self);
|
521
|
+
size = RPTR_DATA(self)->size;
|
522
|
+
num = NUM2LONG(other);
|
523
|
+
return rb_fiddle_ptr_new((char *)ptr - num, size + num, 0);
|
524
|
+
}
|
525
|
+
|
526
|
+
/*
|
527
|
+
* call-seq:
|
528
|
+
* ptr[index] -> an_integer
|
529
|
+
* ptr[start, length] -> a_string
|
530
|
+
*
|
531
|
+
* Returns integer stored at _index_.
|
532
|
+
*
|
533
|
+
* If _start_ and _length_ are given, a string containing the bytes from
|
534
|
+
* _start_ of _length_ will be returned.
|
535
|
+
*/
|
536
|
+
static VALUE
|
537
|
+
rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
|
538
|
+
{
|
539
|
+
VALUE arg0, arg1;
|
540
|
+
VALUE retval = Qnil;
|
541
|
+
size_t offset, len;
|
542
|
+
struct ptr_data *data;
|
543
|
+
|
544
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
545
|
+
if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
|
546
|
+
switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
|
547
|
+
case 1:
|
548
|
+
offset = NUM2ULONG(arg0);
|
549
|
+
retval = INT2NUM(*((char *)data->ptr + offset));
|
550
|
+
break;
|
551
|
+
case 2:
|
552
|
+
offset = NUM2ULONG(arg0);
|
553
|
+
len = NUM2ULONG(arg1);
|
554
|
+
retval = rb_tainted_str_new((char *)data->ptr + offset, len);
|
555
|
+
break;
|
556
|
+
default:
|
557
|
+
rb_bug("rb_fiddle_ptr_aref()");
|
558
|
+
}
|
559
|
+
return retval;
|
560
|
+
}
|
561
|
+
|
562
|
+
/*
|
563
|
+
* call-seq:
|
564
|
+
* ptr[index] = int -> int
|
565
|
+
* ptr[start, length] = string or cptr or addr -> string or dl_cptr or addr
|
566
|
+
*
|
567
|
+
* Set the value at +index+ to +int+.
|
568
|
+
*
|
569
|
+
* Or, set the memory at +start+ until +length+ with the contents of +string+,
|
570
|
+
* the memory from +dl_cptr+, or the memory pointed at by the memory address
|
571
|
+
* +addr+.
|
572
|
+
*/
|
573
|
+
static VALUE
|
574
|
+
rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
|
575
|
+
{
|
576
|
+
VALUE arg0, arg1, arg2;
|
577
|
+
VALUE retval = Qnil;
|
578
|
+
size_t offset, len;
|
579
|
+
void *mem;
|
580
|
+
struct ptr_data *data;
|
581
|
+
|
582
|
+
TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
|
583
|
+
if (!data->ptr) rb_raise(rb_eFiddleError, "NULL pointer dereference");
|
584
|
+
switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
|
585
|
+
case 2:
|
586
|
+
offset = NUM2ULONG(arg0);
|
587
|
+
((char*)data->ptr)[offset] = NUM2UINT(arg1);
|
588
|
+
retval = arg1;
|
589
|
+
break;
|
590
|
+
case 3:
|
591
|
+
offset = NUM2ULONG(arg0);
|
592
|
+
len = NUM2ULONG(arg1);
|
593
|
+
if (RB_TYPE_P(arg2, T_STRING)) {
|
594
|
+
mem = StringValuePtr(arg2);
|
595
|
+
}
|
596
|
+
else if( rb_obj_is_kind_of(arg2, rb_cPointer) ){
|
597
|
+
mem = rb_fiddle_ptr2cptr(arg2);
|
598
|
+
}
|
599
|
+
else{
|
600
|
+
mem = NUM2PTR(arg2);
|
601
|
+
}
|
602
|
+
memcpy((char *)data->ptr + offset, mem, len);
|
603
|
+
retval = arg2;
|
604
|
+
break;
|
605
|
+
default:
|
606
|
+
rb_bug("rb_fiddle_ptr_aset()");
|
607
|
+
}
|
608
|
+
return retval;
|
609
|
+
}
|
610
|
+
|
611
|
+
/*
|
612
|
+
* call-seq: size=(size)
|
613
|
+
*
|
614
|
+
* Set the size of this pointer to +size+
|
615
|
+
*/
|
616
|
+
static VALUE
|
617
|
+
rb_fiddle_ptr_size_set(VALUE self, VALUE size)
|
618
|
+
{
|
619
|
+
RPTR_DATA(self)->size = NUM2LONG(size);
|
620
|
+
return size;
|
621
|
+
}
|
622
|
+
|
623
|
+
/*
|
624
|
+
* call-seq: size
|
625
|
+
*
|
626
|
+
* Get the size of this pointer.
|
627
|
+
*/
|
628
|
+
static VALUE
|
629
|
+
rb_fiddle_ptr_size_get(VALUE self)
|
630
|
+
{
|
631
|
+
return LONG2NUM(RPTR_DATA(self)->size);
|
632
|
+
}
|
633
|
+
|
634
|
+
/*
|
635
|
+
* call-seq:
|
636
|
+
* Fiddle::Pointer[val] => cptr
|
637
|
+
* to_ptr(val) => cptr
|
638
|
+
*
|
639
|
+
* Get the underlying pointer for ruby object +val+ and return it as a
|
640
|
+
* Fiddle::Pointer object.
|
641
|
+
*/
|
642
|
+
static VALUE
|
643
|
+
rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
|
644
|
+
{
|
645
|
+
VALUE ptr, wrap = val, vptr;
|
646
|
+
|
647
|
+
if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
|
648
|
+
rb_io_t *fptr;
|
649
|
+
FILE *fp;
|
650
|
+
GetOpenFile(val, fptr);
|
651
|
+
fp = rb_io_stdio_file(fptr);
|
652
|
+
ptr = rb_fiddle_ptr_new(fp, 0, NULL);
|
653
|
+
}
|
654
|
+
else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
|
655
|
+
char *str = StringValuePtr(val);
|
656
|
+
ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
|
657
|
+
}
|
658
|
+
else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
|
659
|
+
if (rb_obj_is_kind_of(vptr, rb_cPointer)){
|
660
|
+
ptr = vptr;
|
661
|
+
wrap = 0;
|
662
|
+
}
|
663
|
+
else{
|
664
|
+
rb_raise(rb_eFiddleError, "to_ptr should return a Fiddle::Pointer object");
|
665
|
+
}
|
666
|
+
}
|
667
|
+
else{
|
668
|
+
VALUE num = rb_Integer(val);
|
669
|
+
if (num == val) wrap = 0;
|
670
|
+
ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
|
671
|
+
}
|
672
|
+
OBJ_INFECT(ptr, val);
|
673
|
+
if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
|
674
|
+
return ptr;
|
675
|
+
}
|
676
|
+
|
677
|
+
void
|
678
|
+
Init_fiddle_pointer(void)
|
679
|
+
{
|
680
|
+
id_to_ptr = rb_intern("to_ptr");
|
681
|
+
|
682
|
+
/* Document-class: Fiddle::Pointer
|
683
|
+
*
|
684
|
+
* Fiddle::Pointer is a class to handle C pointers
|
685
|
+
*
|
686
|
+
*/
|
687
|
+
rb_cPointer = rb_define_class_under(mFiddle, "Pointer", rb_cObject);
|
688
|
+
rb_define_alloc_func(rb_cPointer, rb_fiddle_ptr_s_allocate);
|
689
|
+
rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
|
690
|
+
rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
|
691
|
+
rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
|
692
|
+
rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
|
693
|
+
rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
|
694
|
+
rb_define_method(rb_cPointer, "free", rb_fiddle_ptr_free_get, 0);
|
695
|
+
rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
|
696
|
+
rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
|
697
|
+
rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
|
698
|
+
rb_define_method(rb_cPointer, "ptr", rb_fiddle_ptr_ptr, 0);
|
699
|
+
rb_define_method(rb_cPointer, "+@", rb_fiddle_ptr_ptr, 0);
|
700
|
+
rb_define_method(rb_cPointer, "ref", rb_fiddle_ptr_ref, 0);
|
701
|
+
rb_define_method(rb_cPointer, "-@", rb_fiddle_ptr_ref, 0);
|
702
|
+
rb_define_method(rb_cPointer, "null?", rb_fiddle_ptr_null_p, 0);
|
703
|
+
rb_define_method(rb_cPointer, "to_s", rb_fiddle_ptr_to_s, -1);
|
704
|
+
rb_define_method(rb_cPointer, "to_str", rb_fiddle_ptr_to_str, -1);
|
705
|
+
rb_define_method(rb_cPointer, "inspect", rb_fiddle_ptr_inspect, 0);
|
706
|
+
rb_define_method(rb_cPointer, "<=>", rb_fiddle_ptr_cmp, 1);
|
707
|
+
rb_define_method(rb_cPointer, "==", rb_fiddle_ptr_eql, 1);
|
708
|
+
rb_define_method(rb_cPointer, "eql?", rb_fiddle_ptr_eql, 1);
|
709
|
+
rb_define_method(rb_cPointer, "+", rb_fiddle_ptr_plus, 1);
|
710
|
+
rb_define_method(rb_cPointer, "-", rb_fiddle_ptr_minus, 1);
|
711
|
+
rb_define_method(rb_cPointer, "[]", rb_fiddle_ptr_aref, -1);
|
712
|
+
rb_define_method(rb_cPointer, "[]=", rb_fiddle_ptr_aset, -1);
|
713
|
+
rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
|
714
|
+
rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
|
715
|
+
|
716
|
+
/* Document-const: NULL
|
717
|
+
*
|
718
|
+
* A NULL pointer
|
719
|
+
*/
|
720
|
+
rb_define_const(mFiddle, "NULL", rb_fiddle_ptr_new(0, 0, 0));
|
721
|
+
}
|