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.
@@ -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
+ }