Ruby: ext/fiddle/pointer.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

pointer.c
Go to the documentation of this file.
1/* -*- C -*-
2 * $Id$
3 */
4
5#include <stdbool.h>
6#include <ruby/ruby.h>
7#include <ruby/io.h>
8
9#ifdef HAVE_RUBY_MEMORY_VIEW_H
10# include <ruby/memory_view.h>
11#endif
12
13#include <ctype.h>
14#include <fiddle.h>
15
16#ifdef PRIsVALUE
17# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
18# define RB_OBJ_STRING(obj) (obj)
19#else
20# define PRIsVALUE "s"
21# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
22# define RB_OBJ_STRING(obj) StringValueCStr(obj)
23#endif
24
25 VALUE rb_cPointer;
26
27 typedef void (*freefunc_t)(void*);
28
29 struct ptr_data {
30 void *ptr;
31 long size;
32 freefunc_t free;
33 bool freed;
34 VALUE wrap[2];
35};
36
37#define RPTR_DATA(obj) ((struct ptr_data *)(DATA_PTR(obj)))
38
39static inline freefunc_t
40get_freefunc(VALUE func, volatile VALUE *wrap)
41{
42 VALUE addrnum;
43 if (NIL_P(func)) {
44 *wrap = 0;
45 return NULL;
46 }
47 addrnum = rb_Integer(func);
48 *wrap = (addrnum != func) ? func : 0;
49 return (freefunc_t)(VALUE)NUM2PTR(addrnum);
50}
51
52static ID id_to_ptr;
53
54static void
55fiddle_ptr_mark(void *ptr)
56{
57 struct ptr_data *data = ptr;
58 if (data->wrap[0]) {
59 rb_gc_mark(data->wrap[0]);
60 }
61 if (data->wrap[1]) {
62 rb_gc_mark(data->wrap[1]);
63 }
64}
65
66static void
67fiddle_ptr_free_ptr(void *ptr)
68{
69 struct ptr_data *data = ptr;
70 if (data->ptr && data->free && !data->freed) {
71 data->freed = true;
72 (*(data->free))(data->ptr);
73 }
74}
75
76static void
77fiddle_ptr_free(void *ptr)
78{
79 fiddle_ptr_free_ptr(ptr);
80 xfree(ptr);
81}
82
83static size_t
84fiddle_ptr_memsize(const void *ptr)
85{
86 const struct ptr_data *data = ptr;
87 return sizeof(*data) + data->size;
88}
89
90static const rb_data_type_t fiddle_ptr_data_type = {
91 "fiddle/pointer",
92 {fiddle_ptr_mark, fiddle_ptr_free, fiddle_ptr_memsize,},
93};
94
95#ifdef FIDDLE_MEMORY_VIEW
96static struct ptr_data *
97fiddle_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
105static bool
106fiddle_ptr_memory_view_available_p(VALUE obj)
107{
108 return fiddle_ptr_check_memory_view(obj) != NULL;
109}
110
111static bool
112fiddle_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 true;
118}
119
120static 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
127static VALUE
128rb_fiddle_ptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
129{
130 struct ptr_data *data;
131 VALUE val;
132
133 val = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
134 data->ptr = ptr;
135 data->free = func;
136 data->freed = false;
137 data->size = size;
138
139 return val;
140}
141
142static VALUE
143rb_fiddle_ptr_new(void *ptr, long size, freefunc_t func)
144{
145 return rb_fiddle_ptr_new2(rb_cPointer, ptr, size, func);
146}
147
148static VALUE
149rb_fiddle_ptr_malloc(VALUE klass, long size, freefunc_t func)
150{
151 void *ptr;
152
153 ptr = ruby_xmalloc((size_t)size);
154 memset(ptr,0,(size_t)size);
155 return rb_fiddle_ptr_new2(klass, ptr, size, func);
156}
157
158static void *
159rb_fiddle_ptr2cptr(VALUE val)
160{
161 struct ptr_data *data;
162 void *ptr;
163
164 if (rb_obj_is_kind_of(val, rb_cPointer)) {
165 TypedData_Get_Struct(val, struct ptr_data, &fiddle_ptr_data_type, data);
166 ptr = data->ptr;
167 }
168 else if (val == Qnil) {
169 ptr = NULL;
170 }
171 else{
172 rb_raise(rb_eTypeError, "Fiddle::Pointer was expected");
173 }
174
175 return ptr;
176}
177
178static VALUE
179rb_fiddle_ptr_s_allocate(VALUE klass)
180{
181 VALUE obj;
182 struct ptr_data *data;
183
184 obj = TypedData_Make_Struct(klass, struct ptr_data, &fiddle_ptr_data_type, data);
185 data->ptr = 0;
186 data->size = 0;
187 data->free = 0;
188 data->freed = false;
189
190 return obj;
191}
192
193/*
194 * call-seq:
195 * Fiddle::Pointer.new(address) => fiddle_cptr
196 * new(address, size) => fiddle_cptr
197 * new(address, size, freefunc) => fiddle_cptr
198 *
199 * Create a new pointer to +address+ with an optional +size+ and +freefunc+.
200 *
201 * +freefunc+ will be called when the instance is garbage collected.
202 */
203static VALUE
204rb_fiddle_ptr_initialize(int argc, VALUE argv[], VALUE self)
205{
206 VALUE ptr, sym, size, wrap = 0, funcwrap = 0;
207 struct ptr_data *data;
208 void *p = NULL;
209 freefunc_t f = NULL;
210 long s = 0;
211
212 if (rb_scan_args(argc, argv, "12", &ptr, &size, &sym) >= 1) {
213 VALUE addrnum = rb_Integer(ptr);
214 if (addrnum != ptr) wrap = ptr;
215 p = NUM2PTR(addrnum);
216 }
217 if (argc >= 2) {
218 s = NUM2LONG(size);
219 }
220 if (argc >= 3) {
221 f = get_freefunc(sym, &funcwrap);
222 }
223
224 if (p) {
225 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
226 if (data->ptr && data->free) {
227 /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
228 (*(data->free))(data->ptr);
229 }
230 data->wrap[0] = wrap;
231 data->wrap[1] = funcwrap;
232 data->ptr = p;
233 data->size = s;
234 data->free = f;
235 }
236
237 return Qnil;
238}
239
240static VALUE
241rb_fiddle_ptr_call_free(VALUE self);
242
243/*
244 * call-seq:
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 * ...
275 *
276 * Allocate +size+ bytes of memory and associate it with an optional
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.
282 *
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+.
287 */
288static VALUE
289rb_fiddle_ptr_s_malloc(int argc, VALUE argv[], VALUE klass)
290{
291 VALUE size, sym, obj, wrap = 0;
292 long s;
293 freefunc_t f;
294
295 switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
296 case 1:
297 s = NUM2LONG(size);
298 f = NULL;
299 break;
300 case 2:
301 s = NUM2LONG(size);
302 f = get_freefunc(sym, &wrap);
303 break;
304 default:
305 rb_bug("rb_fiddle_ptr_s_malloc");
306 }
307
308 obj = rb_fiddle_ptr_malloc(klass, s,f);
309 if (wrap) RPTR_DATA(obj)->wrap[1] = wrap;
310
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 }
319}
320
321/*
322 * call-seq: to_i
323 *
324 * Returns the integer memory location of this pointer.
325 */
326static VALUE
327rb_fiddle_ptr_to_i(VALUE self)
328{
329 struct ptr_data *data;
330
331 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
332 return PTR2NUM(data->ptr);
333}
334
335/*
336 * call-seq: to_value
337 *
338 * Cast this pointer to a ruby object.
339 */
340static VALUE
341rb_fiddle_ptr_to_value(VALUE self)
342{
343 struct ptr_data *data;
344 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
345 return (VALUE)(data->ptr);
346}
347
348/*
349 * call-seq: ptr
350 *
351 * Returns a new Fiddle::Pointer instance that is a dereferenced pointer for
352 * this pointer.
353 *
354 * Analogous to the star operator in C.
355 */
356static VALUE
357rb_fiddle_ptr_ptr(VALUE self)
358{
359 struct ptr_data *data;
360
361 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
362 return rb_fiddle_ptr_new(*((void**)(data->ptr)),0,0);
363}
364
365/*
366 * call-seq: ref
367 *
368 * Returns a new Fiddle::Pointer instance that is a reference pointer for this
369 * pointer.
370 *
371 * Analogous to the ampersand operator in C.
372 */
373static VALUE
374rb_fiddle_ptr_ref(VALUE self)
375{
376 struct ptr_data *data;
377
378 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
379 return rb_fiddle_ptr_new(&(data->ptr),0,0);
380}
381
382/*
383 * call-seq: null?
384 *
385 * Returns +true+ if this is a null pointer.
386 */
387static VALUE
388rb_fiddle_ptr_null_p(VALUE self)
389{
390 struct ptr_data *data;
391
392 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
393 return data->ptr ? Qfalse : Qtrue;
394}
395
396/*
397 * call-seq: free=(function)
398 *
399 * Set the free function for this pointer to +function+ in the given
400 * Fiddle::Function.
401 */
402static VALUE
403rb_fiddle_ptr_free_set(VALUE self, VALUE val)
404{
405 struct ptr_data *data;
406
407 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
408 data->free = get_freefunc(val, &data->wrap[1]);
409
410 return Qnil;
411}
412
413/*
414 * call-seq: free => Fiddle::Function
415 *
416 * Get the free function for this pointer.
417 *
418 * Returns a new instance of Fiddle::Function.
419 *
420 * See Fiddle::Function.new
421 */
422static VALUE
423rb_fiddle_ptr_free_get(VALUE self)
424{
425 struct ptr_data *pdata;
426 VALUE address;
427 VALUE arg_types;
428 VALUE ret_type;
429
430 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, pdata);
431
432 if (!pdata->free)
433 return Qnil;
434
435 address = PTR2NUM(pdata->free);
436 ret_type = INT2NUM(TYPE_VOID);
437 arg_types = rb_ary_new();
438 rb_ary_push(arg_types, INT2NUM(TYPE_VOIDP));
439
440 return rb_fiddle_new_function(address, arg_types, ret_type);
441}
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 */
449static VALUE
450rb_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 */
463static VALUE
464rb_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
471/*
472 * call-seq:
473 *
474 * ptr.to_s => string
475 * ptr.to_s(len) => string
476 *
477 * Returns the pointer contents as a string.
478 *
479 * When called with no arguments, this method will return the contents until
480 * the first NULL byte.
481 *
482 * When called with +len+, a string of +len+ bytes will be returned.
483 *
484 * See to_str
485 */
486static VALUE
487rb_fiddle_ptr_to_s(int argc, VALUE argv[], VALUE self)
488{
489 struct ptr_data *data;
490 VALUE arg1, val;
491 int len;
492
493 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
494 switch (rb_scan_args(argc, argv, "01", &arg1)) {
495 case 0:
496 val = rb_str_new2((char*)(data->ptr));
497 break;
498 case 1:
499 len = NUM2INT(arg1);
500 val = rb_str_new((char*)(data->ptr), len);
501 break;
502 default:
503 rb_bug("rb_fiddle_ptr_to_s");
504 }
505
506 return val;
507}
508
509/*
510 * call-seq:
511 *
512 * ptr.to_str => string
513 * ptr.to_str(len) => string
514 *
515 * Returns the pointer contents as a string.
516 *
517 * When called with no arguments, this method will return the contents with the
518 * length of this pointer's +size+.
519 *
520 * When called with +len+, a string of +len+ bytes will be returned.
521 *
522 * See to_s
523 */
524static VALUE
525rb_fiddle_ptr_to_str(int argc, VALUE argv[], VALUE self)
526{
527 struct ptr_data *data;
528 VALUE arg1, val;
529 int len;
530
531 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
532 switch (rb_scan_args(argc, argv, "01", &arg1)) {
533 case 0:
534 val = rb_str_new((char*)(data->ptr),data->size);
535 break;
536 case 1:
537 len = NUM2INT(arg1);
538 val = rb_str_new((char*)(data->ptr), len);
539 break;
540 default:
541 rb_bug("rb_fiddle_ptr_to_str");
542 }
543
544 return val;
545}
546
547/*
548 * call-seq: inspect
549 *
550 * Returns a string formatted with an easily readable representation of the
551 * internal state of the pointer.
552 */
553static VALUE
554rb_fiddle_ptr_inspect(VALUE self)
555{
556 struct ptr_data *data;
557
558 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
559 return rb_sprintf("#<%"PRIsVALUE":%p ptr=%p size=%ld free=%p>",
560 RB_OBJ_CLASSNAME(self), (void *)data, data->ptr, data->size, (void *)data->free);
561}
562
563/*
564 * call-seq:
565 * ptr == other => true or false
566 * ptr.eql?(other) => true or false
567 *
568 * Returns true if +other+ wraps the same pointer, otherwise returns
569 * false.
570 */
571static VALUE
572rb_fiddle_ptr_eql(VALUE self, VALUE other)
573{
574 void *ptr1, *ptr2;
575
576 if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qfalse;
577
578 ptr1 = rb_fiddle_ptr2cptr(self);
579 ptr2 = rb_fiddle_ptr2cptr(other);
580
581 return ptr1 == ptr2 ? Qtrue : Qfalse;
582}
583
584/*
585 * call-seq:
586 * ptr <=> other => -1, 0, 1, or nil
587 *
588 * Returns -1 if less than, 0 if equal to, 1 if greater than +other+.
589 *
590 * Returns nil if +ptr+ cannot be compared to +other+.
591 */
592static VALUE
593rb_fiddle_ptr_cmp(VALUE self, VALUE other)
594{
595 void *ptr1, *ptr2;
596 SIGNED_VALUE diff;
597
598 if(!rb_obj_is_kind_of(other, rb_cPointer)) return Qnil;
599
600 ptr1 = rb_fiddle_ptr2cptr(self);
601 ptr2 = rb_fiddle_ptr2cptr(other);
602 diff = (SIGNED_VALUE)ptr1 - (SIGNED_VALUE)ptr2;
603 if (!diff) return INT2FIX(0);
604 return diff > 0 ? INT2NUM(1) : INT2NUM(-1);
605}
606
607/*
608 * call-seq:
609 * ptr + n => new cptr
610 *
611 * Returns a new pointer instance that has been advanced +n+ bytes.
612 */
613static VALUE
614rb_fiddle_ptr_plus(VALUE self, VALUE other)
615{
616 void *ptr;
617 long num, size;
618
619 ptr = rb_fiddle_ptr2cptr(self);
620 size = RPTR_DATA(self)->size;
621 num = NUM2LONG(other);
622 return rb_fiddle_ptr_new((char *)ptr + num, size - num, 0);
623}
624
625/*
626 * call-seq:
627 * ptr - n => new cptr
628 *
629 * Returns a new pointer instance that has been moved back +n+ bytes.
630 */
631static VALUE
632rb_fiddle_ptr_minus(VALUE self, VALUE other)
633{
634 void *ptr;
635 long num, size;
636
637 ptr = rb_fiddle_ptr2cptr(self);
638 size = RPTR_DATA(self)->size;
639 num = NUM2LONG(other);
640 return rb_fiddle_ptr_new((char *)ptr - num, size + num, 0);
641}
642
643/*
644 * call-seq:
645 * ptr[index] -> an_integer
646 * ptr[start, length] -> a_string
647 *
648 * Returns integer stored at _index_.
649 *
650 * If _start_ and _length_ are given, a string containing the bytes from
651 * _start_ of _length_ will be returned.
652 */
653static VALUE
654rb_fiddle_ptr_aref(int argc, VALUE argv[], VALUE self)
655{
656 VALUE arg0, arg1;
657 VALUE retval = Qnil;
658 size_t offset, len;
659 struct ptr_data *data;
660
661 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
662 if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
663 switch( rb_scan_args(argc, argv, "11", &arg0, &arg1) ){
664 case 1:
665 offset = NUM2ULONG(arg0);
666 retval = INT2NUM(*((char *)data->ptr + offset));
667 break;
668 case 2:
669 offset = NUM2ULONG(arg0);
670 len = NUM2ULONG(arg1);
671 retval = rb_str_new((char *)data->ptr + offset, len);
672 break;
673 default:
674 rb_bug("rb_fiddle_ptr_aref()");
675 }
676 return retval;
677}
678
679/*
680 * call-seq:
681 * ptr[index] = int -> int
682 * ptr[start, length] = string or cptr or addr -> string or dl_cptr or addr
683 *
684 * Set the value at +index+ to +int+.
685 *
686 * Or, set the memory at +start+ until +length+ with the contents of +string+,
687 * the memory from +dl_cptr+, or the memory pointed at by the memory address
688 * +addr+.
689 */
690static VALUE
691rb_fiddle_ptr_aset(int argc, VALUE argv[], VALUE self)
692{
693 VALUE arg0, arg1, arg2;
694 VALUE retval = Qnil;
695 size_t offset, len;
696 void *mem;
697 struct ptr_data *data;
698
699 TypedData_Get_Struct(self, struct ptr_data, &fiddle_ptr_data_type, data);
700 if (!data->ptr) rb_raise(rb_eFiddleDLError, "NULL pointer dereference");
701 switch( rb_scan_args(argc, argv, "21", &arg0, &arg1, &arg2) ){
702 case 2:
703 offset = NUM2ULONG(arg0);
704 ((char*)data->ptr)[offset] = NUM2UINT(arg1);
705 retval = arg1;
706 break;
707 case 3:
708 offset = NUM2ULONG(arg0);
709 len = NUM2ULONG(arg1);
710 if (RB_TYPE_P(arg2, T_STRING)) {
711 mem = StringValuePtr(arg2);
712 }
713 else if( rb_obj_is_kind_of(arg2, rb_cPointer) ){
714 mem = rb_fiddle_ptr2cptr(arg2);
715 }
716 else{
717 mem = NUM2PTR(arg2);
718 }
719 memcpy((char *)data->ptr + offset, mem, len);
720 retval = arg2;
721 break;
722 default:
723 rb_bug("rb_fiddle_ptr_aset()");
724 }
725 return retval;
726}
727
728/*
729 * call-seq: size=(size)
730 *
731 * Set the size of this pointer to +size+
732 */
733static VALUE
734rb_fiddle_ptr_size_set(VALUE self, VALUE size)
735{
736 RPTR_DATA(self)->size = NUM2LONG(size);
737 return size;
738}
739
740/*
741 * call-seq: size
742 *
743 * Get the size of this pointer.
744 */
745static VALUE
746rb_fiddle_ptr_size_get(VALUE self)
747{
748 return LONG2NUM(RPTR_DATA(self)->size);
749}
750
751/*
752 * call-seq:
753 * Fiddle::Pointer[val] => cptr
754 * to_ptr(val) => cptr
755 *
756 * Get the underlying pointer for ruby object +val+ and return it as a
757 * Fiddle::Pointer object.
758 */
759static VALUE
760rb_fiddle_ptr_s_to_ptr(VALUE self, VALUE val)
761{
762 VALUE ptr, wrap = val, vptr;
763
764 if (RTEST(rb_obj_is_kind_of(val, rb_cIO))){
765 rb_io_t *fptr;
766 FILE *fp;
767 GetOpenFile(val, fptr);
768 fp = rb_io_stdio_file(fptr);
769 ptr = rb_fiddle_ptr_new(fp, 0, NULL);
770 }
771 else if (RTEST(rb_obj_is_kind_of(val, rb_cString))){
772 char *str = StringValuePtr(val);
773 ptr = rb_fiddle_ptr_new(str, RSTRING_LEN(val), NULL);
774 }
775 else if ((vptr = rb_check_funcall(val, id_to_ptr, 0, 0)) != Qundef){
776 if (rb_obj_is_kind_of(vptr, rb_cPointer)){
777 ptr = vptr;
778 wrap = 0;
779 }
780 else{
781 rb_raise(rb_eFiddleDLError, "to_ptr should return a Fiddle::Pointer object");
782 }
783 }
784 else{
785 VALUE num = rb_Integer(val);
786 if (num == val) wrap = 0;
787 ptr = rb_fiddle_ptr_new(NUM2PTR(num), 0, NULL);
788 }
789 if (wrap) RPTR_DATA(ptr)->wrap[0] = wrap;
790 return ptr;
791}
792
793void
794 Init_fiddle_pointer(void)
795{
796#undef rb_intern
797 id_to_ptr = rb_intern("to_ptr");
798
799 /* Document-class: Fiddle::Pointer
800 *
801 * Fiddle::Pointer is a class to handle C pointers
802 *
803 */
804 rb_cPointer = rb_define_class_under(mFiddle, "Pointer", rb_cObject);
805 rb_define_alloc_func(rb_cPointer, rb_fiddle_ptr_s_allocate);
806 rb_define_singleton_method(rb_cPointer, "malloc", rb_fiddle_ptr_s_malloc, -1);
807 rb_define_singleton_method(rb_cPointer, "to_ptr", rb_fiddle_ptr_s_to_ptr, 1);
808 rb_define_singleton_method(rb_cPointer, "[]", rb_fiddle_ptr_s_to_ptr, 1);
809 rb_define_method(rb_cPointer, "initialize", rb_fiddle_ptr_initialize, -1);
810 rb_define_method(rb_cPointer, "free=", rb_fiddle_ptr_free_set, 1);
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);
814 rb_define_method(rb_cPointer, "to_i", rb_fiddle_ptr_to_i, 0);
815 rb_define_method(rb_cPointer, "to_int", rb_fiddle_ptr_to_i, 0);
816 rb_define_method(rb_cPointer, "to_value", rb_fiddle_ptr_to_value, 0);
817 rb_define_method(rb_cPointer, "ptr", rb_fiddle_ptr_ptr, 0);
818 rb_define_method(rb_cPointer, "+@", rb_fiddle_ptr_ptr, 0);
819 rb_define_method(rb_cPointer, "ref", rb_fiddle_ptr_ref, 0);
820 rb_define_method(rb_cPointer, "-@", rb_fiddle_ptr_ref, 0);
821 rb_define_method(rb_cPointer, "null?", rb_fiddle_ptr_null_p, 0);
822 rb_define_method(rb_cPointer, "to_s", rb_fiddle_ptr_to_s, -1);
823 rb_define_method(rb_cPointer, "to_str", rb_fiddle_ptr_to_str, -1);
824 rb_define_method(rb_cPointer, "inspect", rb_fiddle_ptr_inspect, 0);
825 rb_define_method(rb_cPointer, "<=>", rb_fiddle_ptr_cmp, 1);
826 rb_define_method(rb_cPointer, "==", rb_fiddle_ptr_eql, 1);
827 rb_define_method(rb_cPointer, "eql?", rb_fiddle_ptr_eql, 1);
828 rb_define_method(rb_cPointer, "+", rb_fiddle_ptr_plus, 1);
829 rb_define_method(rb_cPointer, "-", rb_fiddle_ptr_minus, 1);
830 rb_define_method(rb_cPointer, "[]", rb_fiddle_ptr_aref, -1);
831 rb_define_method(rb_cPointer, "[]=", rb_fiddle_ptr_aset, -1);
832 rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
833 rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
834
835#ifdef FIDDLE_MEMORY_VIEW
836 rb_memory_view_register(rb_cPointer, &fiddle_ptr_memory_view_entry);
837#endif
838
839 /* Document-const: NULL
840 *
841 * A NULL pointer
842 */
843 rb_define_const(mFiddle, "NULL", rb_fiddle_ptr_new(0, 0, 0));
844}
rb_ary_push
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
rb_ary_new
VALUE rb_ary_new(void)
Definition: array.c:749
NUM2PTR
#define NUM2PTR(x)
Definition: conversions.h:46
PTR2NUM
#define PTR2NUM(x)
Definition: conversions.h:45
ctype.h
Our own, locale independent, character handling routines.
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
rb_define_singleton_method
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
ptr
struct RIMemo * ptr
Definition: debug.c:88
num
big_t * num
Definition: enough.c:232
sym
#define sym(name)
Definition: enumerator.c:4007
len
uint8_t len
Definition: escape.c:17
str
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
RSTRING_LEN
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
memcpy
#define memcpy(d, s, n)
Definition: ffi_common.h:55
mFiddle
VALUE mFiddle
Definition: fiddle.c:3
rb_eFiddleDLError
VALUE rb_eFiddleDLError
Definition: fiddle.c:4
fiddle.h
TYPE_VOID
#define TYPE_VOID
Definition: fiddle.h:107
rb_fiddle_new_function
VALUE rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
Definition: function.c:69
TYPE_VOIDP
#define TYPE_VOIDP
Definition: fiddle.h:108
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_gc_mark
void rb_gc_mark(VALUE ptr)
Definition: gc.c:6112
ruby_xmalloc
void * ruby_xmalloc(size_t size)
Allocates a storage instance.
Definition: gc.c:12795
rb_cIO
VALUE rb_cIO
Definition: io.c:183
rb_cString
VALUE rb_cString
Definition: string.c:80
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:797
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
rb_block_given_p
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:935
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_bug
void rb_bug(const char *fmt,...)
Definition: error.c:768
rb_eTypeError
VALUE rb_eTypeError
Definition: error.c:1057
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1148
rb_cObject
VALUE rb_cObject
Object class.
Definition: object.c:49
rb_Integer
VALUE rb_Integer(VALUE)
Equivalent to Kernel#Integer in Ruby.
Definition: object.c:3138
rb_obj_is_kind_of
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:724
rb_str_new2
#define rb_str_new2
Definition: string.h:276
rb_str_new
#define rb_str_new(str, len)
Definition: string.h:213
rb_check_funcall
VALUE rb_check_funcall(VALUE, ID, int, const VALUE *)
Definition: vm_eval.c:619
rb_define_alloc_func
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
rb_define_const
void rb_define_const(VALUE, const char *, VALUE)
Definition: variable.c:3150
io.h
GetOpenFile
#define GetOpenFile
Definition: io.h:125
rb_io_stdio_file
FILE * rb_io_stdio_file(rb_io_t *fptr)
Definition: io.c:8229
NUM2UINT
#define NUM2UINT
Definition: int.h:45
NUM2INT
#define NUM2INT
Definition: int.h:44
INT2NUM
#define INT2NUM
Definition: int.h:43
size
voidpf void uLong size
Definition: ioapi.h:138
offset
voidpf uLong offset
Definition: ioapi.h:144
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:1341
NUM2ULONG
#define NUM2ULONG
Definition: long.h:52
INT2FIX
#define INT2FIX
Definition: long.h:48
LONG2NUM
#define LONG2NUM
Definition: long.h:50
NUM2LONG
#define NUM2LONG
Definition: long.h:51
memory_view.h
Memory View.
rb_memory_view_register
bool rb_memory_view_register(VALUE klass, const rb_memory_view_entry_t *entry)
Definition: memory_view.c:131
rb_memory_view_init_as_byte_array
bool rb_memory_view_init_as_byte_array(rb_memory_view_t *view, VALUE obj, void *data, const ssize_t len, const bool readonly)
Definition: memory_view.c:198
RB_OBJ_CLASSNAME
#define RB_OBJ_CLASSNAME(obj)
Definition: pointer.c:17
Init_fiddle_pointer
void Init_fiddle_pointer(void)
Definition: pointer.c:794
freefunc_t
void(* freefunc_t)(void *)
Definition: pointer.c:27
RPTR_DATA
#define RPTR_DATA(obj)
Definition: pointer.c:37
rb_cPointer
VALUE rb_cPointer
Definition: pointer.c:25
NULL
#define NULL
Definition: regenc.h:69
StringValuePtr
#define StringValuePtr(v)
Definition: rstring.h:51
TypedData_Get_Struct
#define TypedData_Get_Struct(obj, type, data_type, sval)
Definition: rtypeddata.h:130
TypedData_Make_Struct
#define TypedData_Make_Struct(klass, type, data_type, sval)
Definition: rtypeddata.h:122
ruby.h
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
Qundef
#define Qundef
Definition: special_consts.h:53
Qtrue
#define Qtrue
Definition: special_consts.h:52
RTEST
#define RTEST
Definition: special_consts.h:42
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
NIL_P
#define NIL_P
Definition: special_consts.h:46
f
#define f
rb_sprintf
VALUE rb_sprintf(const char *,...)
Definition: sprintf.c:1203
stdbool.h
C99 shim for <stdbool.h>
__sFILE
Definition: vsnprintf.c:169
ptr_data
Definition: pointer.c:29
ptr_data::ptr
void * ptr
Definition: pointer.c:30
ptr_data::freed
bool freed
Definition: pointer.c:33
ptr_data::free
freefunc_t free
Definition: pointer.c:32
ptr_data::size
long size
Definition: pointer.c:31
ptr_data::wrap
VALUE wrap[2]
Definition: pointer.c:34
rb_data_type_struct
Definition: rtypeddata.h:70
rb_io_t
Definition: io.h:61
rb_memory_view_entry_t
Definition: memory_view.h:112
rb_memory_view_t
Definition: memory_view.h:39
VALUE
unsigned long VALUE
Definition: value.h:38
SIGNED_VALUE
#define SIGNED_VALUE
Definition: value.h:40
ID
unsigned long ID
Definition: value.h:39
T_STRING
#define T_STRING
Definition: value_type.h:77
xfree
#define xfree
Definition: xmalloc.h:49