Added spec for Kernel#eval with binding from method defined by #eval.
[rbx.git] / stdlib / ext / dl / ptr.c
blobd34d160e0d6dc4f54896d200b158823a8f9eb618
1 /* -*- C -*-
2 * $Id: ptr.c 12039 2007-03-11 16:24:34Z knu $
3 */
5 #include <ruby.h>
6 #include <ctype.h>
7 #include <version.h> /* for ruby version code */
8 #include "dl.h"
10 VALUE rb_cDLPtrData;
11 VALUE rb_mDLMemorySpace;
12 static VALUE DLMemoryTable;
14 #ifndef T_SYMBOL
15 # define T_SYMBOL T_FIXNUM
16 #endif
18 #if RUBY_VERSION_CODE < 171
19 static VALUE
20 rb_hash_delete(VALUE hash, VALUE key)
22 return rb_funcall(hash, rb_intern("delete"), 1, key);
24 #endif
26 static void
27 rb_dlmem_delete(void *ptr)
29 rb_secure(4);
30 rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr));
33 static void
34 rb_dlmem_aset(void *ptr, VALUE obj)
36 if (obj == Qnil) {
37 rb_dlmem_delete(ptr);
39 else{
40 rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj));
44 static VALUE
45 rb_dlmem_aref(void *ptr)
47 VALUE val;
49 val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr));
50 return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val);
53 void
54 dlptr_free(struct ptr_data *data)
56 if (data->ptr) {
57 DEBUG_CODE({
58 printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n",
59 data->ptr);
60 });
61 rb_dlmem_delete(data->ptr);
62 if (data->free) {
63 DEBUG_CODE({
64 printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr);
65 });
66 (*(data->free))(data->ptr);
69 if (data->stype) dlfree(data->stype);
70 if (data->ssize) dlfree(data->ssize);
71 if (data->ids) dlfree(data->ids);
74 void
75 dlptr_init(VALUE val)
77 struct ptr_data *data;
79 Data_Get_Struct(val, struct ptr_data, data);
80 DEBUG_CODE({
81 printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n",
82 data->ptr);
83 });
84 rb_dlmem_aset(data->ptr, val);
85 OBJ_TAINT(val);
88 VALUE
89 rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
91 struct ptr_data *data;
92 VALUE val;
94 rb_secure(4);
95 if (ptr) {
96 val = rb_dlmem_aref(ptr);
97 if (val == Qnil) {
98 val = Data_Make_Struct(klass, struct ptr_data,
99 0, dlptr_free, data);
100 data->ptr = ptr;
101 data->free = func;
102 data->ctype = DLPTR_CTYPE_UNKNOWN;
103 data->stype = NULL;
104 data->ssize = NULL;
105 data->slen = 0;
106 data->size = size;
107 data->ids = NULL;
108 data->ids_num = 0;
109 dlptr_init(val);
111 else{
112 if (func) {
113 Data_Get_Struct(val, struct ptr_data, data);
114 data->free = func;
118 else{
119 val = Qnil;
122 return val;
125 VALUE
126 rb_dlptr_new(void *ptr, long size, freefunc_t func)
128 return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func);
131 VALUE
132 rb_dlptr_malloc(long size, freefunc_t func)
134 void *ptr;
136 rb_secure(4);
137 ptr = dlmalloc((size_t)size);
138 memset(ptr,0,(size_t)size);
139 return rb_dlptr_new(ptr, size, func);
142 void *
143 rb_dlptr2cptr(VALUE val)
145 struct ptr_data *data;
146 void *ptr;
148 if (rb_obj_is_kind_of(val, rb_cDLPtrData)) {
149 Data_Get_Struct(val, struct ptr_data, data);
150 ptr = data->ptr;
152 else if (val == Qnil) {
153 ptr = NULL;
155 else{
156 rb_raise(rb_eTypeError, "DL::PtrData was expected");
159 return ptr;
162 static VALUE
163 rb_dlptr_s_allocate(VALUE klass)
165 VALUE obj;
166 struct ptr_data *data;
168 rb_secure(4);
169 obj = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data);
170 data->ptr = 0;
171 data->free = 0;
172 data->ctype = DLPTR_CTYPE_UNKNOWN;
173 data->stype = NULL;
174 data->ssize = NULL;
175 data->slen = 0;
176 data->size = 0;
177 data->ids = NULL;
178 data->ids_num = 0;
180 return obj;
183 static VALUE
184 rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
186 VALUE ptr, sym, size;
187 struct ptr_data *data;
188 void *p = NULL;
189 freefunc_t f = NULL;
190 long s = 0;
192 switch (rb_scan_args(argc, argv, "12", &ptr, &size, &sym)) {
193 case 1:
194 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
195 break;
196 case 2:
197 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
198 s = DLNUM2LONG(size);
199 break;
200 case 3:
201 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
202 s = DLNUM2LONG(size);
203 f = rb_dlsym2csym(sym);
204 break;
205 default:
206 rb_bug("rb_dlptr_initialize");
209 if (p) {
210 Data_Get_Struct(self, struct ptr_data, data);
211 if (data->ptr && data->free) {
212 /* Free previous memory. Use of inappropriate initialize may cause SEGV. */
213 (*(data->free))(data->ptr);
215 data->ptr = p;
216 data->size = s;
217 data->free = f;
220 return Qnil;
223 static VALUE
224 rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
226 VALUE size, sym, obj;
227 int s;
228 freefunc_t f = NULL;
230 switch (rb_scan_args(argc, argv, "11", &size, &sym)) {
231 case 1:
232 s = NUM2INT(size);
233 break;
234 case 2:
235 s = NUM2INT(size);
236 f = rb_dlsym2csym(sym);
237 break;
238 default:
239 rb_bug("rb_dlptr_s_malloc");
242 obj = rb_dlptr_malloc(s,f);
244 return obj;
247 VALUE
248 rb_dlptr_to_i(VALUE self)
250 struct ptr_data *data;
252 Data_Get_Struct(self, struct ptr_data, data);
253 return DLLONG2NUM(data->ptr);
256 VALUE
257 rb_dlptr_ptr(VALUE self)
259 struct ptr_data *data;
261 Data_Get_Struct(self, struct ptr_data, data);
262 return rb_dlptr_new(*((void**)(data->ptr)),0,0);
265 VALUE
266 rb_dlptr_ref(VALUE self)
268 struct ptr_data *data;
270 Data_Get_Struct(self, struct ptr_data, data);
271 return rb_dlptr_new(&(data->ptr),0,0);
274 VALUE
275 rb_dlptr_null_p(VALUE self)
277 struct ptr_data *data;
279 Data_Get_Struct(self, struct ptr_data, data);
280 return data->ptr ? Qfalse : Qtrue;
283 VALUE
284 rb_dlptr_free_set(VALUE self, VALUE val)
286 struct ptr_data *data;
288 Data_Get_Struct(self, struct ptr_data, data);
290 data->free = DLFREEFUNC(rb_dlsym2csym(val));
292 return Qnil;
295 VALUE
296 rb_dlptr_free_get(VALUE self)
298 struct ptr_data *pdata;
300 Data_Get_Struct(self, struct ptr_data, pdata);
302 return rb_dlsym_new(pdata->free,"(free)","0P");
305 VALUE
306 rb_dlptr_to_array(int argc, VALUE argv[], VALUE self)
308 struct ptr_data *data;
309 int n;
310 int i;
311 int t;
312 VALUE ary;
313 VALUE type, size;
315 Data_Get_Struct(self, struct ptr_data, data);
317 switch (rb_scan_args(argc, argv, "11", &type, &size)) {
318 case 2:
319 t = StringValuePtr(type)[0];
320 n = NUM2INT(size);
321 break;
322 case 1:
323 t = StringValuePtr(type)[0];
324 switch (t) {
325 case 'C':
326 n = data->size;
327 break;
328 case 'H':
329 n = data->size / sizeof(short);
330 break;
331 case 'I':
332 n = data->size / sizeof(int);
333 break;
334 case 'L':
335 n = data->size / sizeof(long);
336 break;
337 case 'F':
338 n = data->size / sizeof(float);
339 break;
340 case 'D':
341 n = data->size / sizeof(double);
342 break;
343 case 'P': case 'p':
344 n = data->size / sizeof(void*);
345 break;
346 case 'S': case 's':
347 for (n=0; ((void**)(data->ptr))[n]; n++) {};
348 break;
349 default:
350 n = 0;
352 break;
353 default:
354 rb_bug("rb_dlptr_to_array");
357 ary = rb_ary_new();
359 for (i=0; i < n; i++) {
360 switch (t) {
361 case 'C':
362 rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i]));
363 break;
364 case 'H':
365 rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i]));
366 break;
367 case 'I':
368 rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i]));
369 break;
370 case 'L':
371 rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i]));
372 break;
373 case 'D':
374 rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i]));
375 break;
376 case 'F':
377 rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i]));
378 break;
379 case 'S':
381 char *str = ((char**)(data->ptr))[i];
382 if (str) {
383 rb_ary_push(ary, rb_tainted_str_new2(str));
385 else{
386 rb_ary_push(ary, Qnil);
389 break;
390 case 's':
392 char *str = ((char**)(data->ptr))[i];
393 if (str) {
394 rb_ary_push(ary, rb_tainted_str_new2(str));
395 xfree(str);
397 else{
398 rb_ary_push(ary, Qnil);
401 break;
402 case 'P':
403 rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0));
404 break;
405 case 'p':
406 rb_ary_push(ary,
407 rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree));
408 break;
412 return ary;
416 VALUE
417 rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
419 struct ptr_data *data;
420 VALUE arg1, val;
421 int len;
423 Data_Get_Struct(self, struct ptr_data, data);
424 switch (rb_scan_args(argc, argv, "01", &arg1)) {
425 case 0:
426 val = rb_tainted_str_new2((char*)(data->ptr));
427 break;
428 case 1:
429 len = NUM2INT(arg1);
430 val = rb_tainted_str_new((char*)(data->ptr), len);
431 break;
432 default:
433 rb_bug("rb_dlptr_to_s");
436 return val;
439 VALUE
440 rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
442 struct ptr_data *data;
443 VALUE arg1, val;
444 int len;
446 Data_Get_Struct(self, struct ptr_data, data);
447 switch (rb_scan_args(argc, argv, "01", &arg1)) {
448 case 0:
449 val = rb_tainted_str_new((char*)(data->ptr),data->size);
450 break;
451 case 1:
452 len = NUM2INT(arg1);
453 val = rb_tainted_str_new((char*)(data->ptr), len);
454 break;
455 default:
456 rb_bug("rb_dlptr_to_str");
459 return val;
462 VALUE
463 rb_dlptr_inspect(VALUE self)
465 struct ptr_data *data;
466 char str[1024];
468 Data_Get_Struct(self, struct ptr_data, data);
469 snprintf(str, 1023, "#<%s:0x%x ptr=0x%x size=%ld free=0x%x>",
470 rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, data->free);
471 return rb_str_new2(str);
474 VALUE
475 rb_dlptr_eql(VALUE self, VALUE other)
477 void *ptr1, *ptr2;
478 ptr1 = rb_dlptr2cptr(self);
479 ptr2 = rb_dlptr2cptr(other);
481 return ptr1 == ptr2 ? Qtrue : Qfalse;
484 VALUE
485 rb_dlptr_cmp(VALUE self, VALUE other)
487 void *ptr1, *ptr2;
488 ptr1 = rb_dlptr2cptr(self);
489 ptr2 = rb_dlptr2cptr(other);
490 return DLLONG2NUM((long)ptr1 - (long)ptr2);
493 VALUE
494 rb_dlptr_plus(VALUE self, VALUE other)
496 void *ptr;
497 long num, size;
499 ptr = rb_dlptr2cptr(self);
500 size = RDLPTR(self)->size;
501 num = DLNUM2LONG(other);
502 return rb_dlptr_new((char *)ptr + num, size - num, 0);
505 VALUE
506 rb_dlptr_minus(VALUE self, VALUE other)
508 void *ptr;
509 long num, size;
511 ptr = rb_dlptr2cptr(self);
512 size = RDLPTR(self)->size;
513 num = DLNUM2LONG(other);
514 return rb_dlptr_new((char *)ptr - num, size + num, 0);
517 VALUE
518 rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self)
520 VALUE data_type, type, rest, vid;
521 struct ptr_data *data;
522 int i, t, num;
523 char *ctype;
525 rb_scan_args(argc, argv, "11*", &data_type, &type, &rest);
526 Data_Get_Struct(self, struct ptr_data, data);
528 if (argc == 1 || (argc == 2 && type == Qnil)) {
529 if (NUM2INT(data_type) == DLPTR_CTYPE_UNKNOWN) {
530 data->ctype = DLPTR_CTYPE_UNKNOWN;
531 data->slen = 0;
532 data->ids_num = 0;
533 if (data->stype) {
534 dlfree(data->stype);
535 data->stype = NULL;
537 if (data->ids) {
538 dlfree(data->ids);
539 data->ids = NULL;
541 return Qnil;
543 else{
544 rb_raise(rb_eArgError, "wrong arguments");
548 t = NUM2INT(data_type);
549 StringValue(type);
550 Check_Type(rest, T_ARRAY);
551 num = RARRAY(rest)->len;
552 for (i=0; i<num; i++) {
553 rb_to_id(rb_ary_entry(rest,i));
556 data->ctype = t;
557 data->slen = num;
558 data->ids_num = num;
559 if (data->stype) dlfree(data->stype);
560 data->stype = (char*)dlmalloc(sizeof(char) * num);
561 if (data->ssize) dlfree(data->ssize);
562 data->ssize = (int*)dlmalloc(sizeof(int) * num);
563 if (data->ids) dlfree(data->ids);
564 data->ids = (ID*)dlmalloc(sizeof(ID) * data->ids_num);
566 ctype = StringValuePtr(type);
567 for (i=0; i<num; i++) {
568 vid = rb_ary_entry(rest,i);
569 data->ids[i] = rb_to_id(vid);
570 data->stype[i] = *ctype;
571 ctype ++;
572 if (isdigit(*ctype)) {
573 char *p, *d;
574 for (p=ctype; isdigit(*p); p++) ;
575 d = ALLOCA_N(char, p - ctype + 1);
576 strncpy(d, ctype, p - ctype);
577 d[p - ctype] = '\0';
578 data->ssize[i] = atoi(d);
579 ctype = p;
581 else{
582 data->ssize[i] = 1;
586 if (*ctype) {
587 rb_raise(rb_eArgError, "too few/many arguments");
590 if (!data->size)
591 data->size = dlsizeof(RSTRING(type)->ptr);
593 return Qnil;
596 VALUE
597 rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self)
599 VALUE *pass_argv;
600 int pass_argc, i;
602 pass_argc = argc + 1;
603 pass_argv = ALLOCA_N(VALUE, pass_argc);
604 pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT);
605 for (i=1; i<pass_argc; i++) {
606 pass_argv[i] = argv[i-1];
608 return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
611 VALUE
612 rb_dlptr_define_union(int argc, VALUE argv[], VALUE self)
614 VALUE *pass_argv;
615 int pass_argc, i;
617 pass_argc = argc + 1;
618 pass_argv = ALLOCA_N(VALUE, pass_argc);
619 pass_argv[0] = INT2FIX(DLPTR_CTYPE_UNION);
620 for (i=1; i<pass_argc; i++) {
621 pass_argv[i] = argv[i-1];
623 return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
626 VALUE
627 rb_dlptr_get_data_type(VALUE self)
629 struct ptr_data *data;
631 Data_Get_Struct(self, struct ptr_data, data);
632 if (data->stype)
633 return rb_assoc_new(INT2FIX(data->ctype),
634 rb_tainted_str_new(data->stype, data->slen));
635 else
636 return rb_assoc_new(INT2FIX(data->ctype), Qnil);
639 static VALUE
640 cary2ary(void *ptr, char t, int len)
642 VALUE ary;
643 VALUE elem;
644 int i;
646 if (len < 1)
647 return Qnil;
649 if (len == 1) {
650 switch (t) {
651 case 'I':
652 elem = INT2NUM(*((int*)ptr));
653 ptr = (char *)ptr + sizeof(int);
654 break;
655 case 'L':
656 elem = DLLONG2NUM(*((long*)ptr));
657 ptr = (char *)ptr + sizeof(long);
658 break;
659 case 'P':
660 case 'S':
661 elem = rb_dlptr_new(*((void**)ptr),0, 0);
662 ptr = (char *)ptr + sizeof(void*);
663 break;
664 case 'F':
665 elem = rb_float_new(*((float*)ptr));
666 ptr = (char *)ptr + sizeof(float);
667 break;
668 case 'D':
669 elem = rb_float_new(*((double*)ptr));
670 ptr = (char *)ptr + sizeof(double);
671 break;
672 case 'C':
673 elem = INT2NUM(*((char*)ptr));
674 ptr = (char *)ptr + sizeof(char);
675 break;
676 case 'H':
677 elem = INT2NUM(*((short*)ptr));
678 ptr = (char *)ptr + sizeof(short);
679 break;
680 default:
681 rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
683 return elem;
686 ary = rb_ary_new();
687 for (i=0; i < len; i++) {
688 switch (t) {
689 case 'I':
690 elem = INT2NUM(*((int*)ptr));
691 ptr = (char *)ptr + sizeof(int);
692 break;
693 case 'L':
694 elem = DLLONG2NUM(*((long*)ptr));
695 ptr = (char *)ptr + sizeof(long);
696 break;
697 case 'P':
698 case 'S':
699 elem = rb_dlptr_new(*((void**)ptr), 0, 0);
700 ptr = (char *)ptr + sizeof(void*);
701 break;
702 case 'F':
703 elem = rb_float_new(*((float*)ptr));
704 ptr = (char *)ptr + sizeof(float);
705 break;
706 case 'D':
707 elem = rb_float_new(*((float*)ptr));
708 ptr = (char *)ptr + sizeof(double);
709 break;
710 case 'C':
711 elem = INT2NUM(*((char*)ptr));
712 ptr = (char *)ptr + sizeof(char);
713 break;
714 case 'H':
715 elem = INT2NUM(*((short*)ptr));
716 ptr = (char *)ptr + sizeof(short);
717 break;
718 default:
719 rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
721 rb_ary_push(ary, elem);
724 return ary;
727 VALUE
728 rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
730 VALUE key = Qnil, num = Qnil;
731 ID id;
732 struct ptr_data *data;
733 int i;
734 int offset;
736 if (rb_scan_args(argc, argv, "11", &key, &num) == 1) {
737 num = INT2NUM(0);
740 if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) {
741 VALUE pass[1];
742 pass[0] = num;
743 return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key));
745 rb_to_id(key);
746 if (! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL)) {
747 rb_raise(rb_eTypeError, "the key must be a string or symbol");
750 id = rb_to_id(key);
751 Data_Get_Struct(self, struct ptr_data, data);
752 offset = 0;
753 switch (data->ctype) {
754 case DLPTR_CTYPE_STRUCT:
755 for (i=0; i < data->ids_num; i++) {
756 switch (data->stype[i]) {
757 case 'I':
758 DLALIGN(data->ptr,offset,INT_ALIGN);
759 break;
760 case 'L':
761 DLALIGN(data->ptr,offset,LONG_ALIGN);
762 break;
763 case 'P':
764 case 'S':
765 DLALIGN(data->ptr,offset,VOIDP_ALIGN);
766 break;
767 case 'F':
768 DLALIGN(data->ptr,offset,FLOAT_ALIGN);
769 break;
770 case 'D':
771 DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
772 break;
773 case 'C':
774 break;
775 case 'H':
776 DLALIGN(data->ptr,offset,SHORT_ALIGN);
777 break;
778 default:
779 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
781 if (data->ids[i] == id) {
782 return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]);
784 switch (data->stype[i]) {
785 case 'I':
786 offset += sizeof(int) * data->ssize[i];
787 break;
788 case 'L':
789 offset += sizeof(long) * data->ssize[i];
790 break;
791 case 'P':
792 case 'S':
793 offset += sizeof(void*) * data->ssize[i];
794 break;
795 case 'F':
796 offset += sizeof(float) * data->ssize[i];
797 break;
798 case 'D':
799 offset += sizeof(double) * data->ssize[i];
800 break;
801 case 'C':
802 offset += sizeof(char) * data->ssize[i];
803 break;
804 case 'H':
805 offset += sizeof(short) * data->ssize[i];
806 break;
807 default:
808 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
811 break;
812 case DLPTR_CTYPE_UNION:
813 for (i=0; i < data->ids_num; i++) {
814 if (data->ids[i] == id) {
815 return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]);
818 break;
819 } /* end of switch */
821 rb_raise(rb_eNameError, "undefined key `%s' for %s",
822 rb_id2name(id), rb_class2name(CLASS_OF(self)));
824 return Qnil;
827 static void *
828 ary2cary(char t, VALUE val, long *size)
830 void *ptr;
832 if (TYPE(val) == T_ARRAY) {
833 ptr = rb_ary2cary(t, val, size);
835 else{
836 ptr = rb_ary2cary(t, rb_ary_new3(1, val), size);
838 return ptr;
841 VALUE
842 rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
844 VALUE key = Qnil, num = Qnil, val = Qnil;
845 ID id;
846 struct ptr_data *data;
847 int i;
848 int offset;
849 long memsize;
850 void *memimg;
852 rb_secure(4);
853 switch (rb_scan_args(argc, argv, "21", &key, &num, &val)) {
854 case 2:
855 val = num;
856 num = Qnil;
857 break;
860 if (TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM) {
861 void *dst, *src;
862 long len;
864 StringValue(val);
865 Data_Get_Struct(self, struct ptr_data, data);
866 dst = (void*)((long)(data->ptr) + DLNUM2LONG(key));
867 src = RSTRING(val)->ptr;
868 len = RSTRING(val)->len;
869 if (num == Qnil) {
870 memcpy(dst, src, len);
872 else{
873 long n = NUM2INT(num);
874 memcpy(dst, src, n < len ? n : len);
875 if (n > len) MEMZERO((char*)dst + len, char, n - len);
877 return val;
880 id = rb_to_id(key);
881 Data_Get_Struct(self, struct ptr_data, data);
882 switch (data->ctype) {
883 case DLPTR_CTYPE_STRUCT:
884 offset = 0;
885 for (i=0; i < data->ids_num; i++) {
886 switch (data->stype[i]) {
887 case 'I':
888 DLALIGN(data->ptr,offset,INT_ALIGN);
889 break;
890 case 'L':
891 DLALIGN(data->ptr,offset,LONG_ALIGN);
892 break;
893 case 'P':
894 case 'S':
895 DLALIGN(data->ptr,offset,VOIDP_ALIGN);
896 break;
897 case 'D':
898 DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
899 break;
900 case 'F':
901 DLALIGN(data->ptr,offset,FLOAT_ALIGN);
902 break;
903 case 'C':
904 break;
905 case 'H':
906 DLALIGN(data->ptr,offset,SHORT_ALIGN);
907 break;
908 default:
909 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
911 if (data->ids[i] == id) {
912 memimg = ary2cary(data->stype[i], val, &memsize);
913 memcpy((char *)data->ptr + offset, memimg, memsize);
914 dlfree(memimg);
915 return val;
917 switch (data->stype[i]) {
918 case 'I':
919 case 'i':
920 offset += sizeof(int) * data->ssize[i];
921 break;
922 case 'L':
923 case 'l':
924 offset += sizeof(long) * data->ssize[i];
925 break;
926 case 'P':
927 case 'p':
928 case 'S':
929 case 's':
930 offset += sizeof(void*) * data->ssize[i];
931 break;
932 case 'D':
933 case 'd':
934 offset += sizeof(double) * data->ssize[i];
935 break;
936 case 'F':
937 case 'f':
938 offset += sizeof(float) * data->ssize[i];
939 break;
940 case 'C':
941 case 'c':
942 offset += sizeof(char) * data->ssize[i];
943 break;
944 case 'H':
945 case 'h':
946 offset += sizeof(short) * data->ssize[i];
947 break;
948 default:
949 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
952 return val;
953 /* break; */
954 case DLPTR_CTYPE_UNION:
955 for (i=0; i < data->ids_num; i++) {
956 if (data->ids[i] == id) {
957 switch (data->stype[i]) {
958 case 'I': case 'i':
959 memsize = sizeof(int) * data->ssize[i];
960 break;
961 case 'L': case 'l':
962 memsize = sizeof(long) * data->ssize[i];
963 break;
964 case 'P': case 'p':
965 case 'S': case 's':
966 memsize = sizeof(void*) * data->ssize[i];
967 break;
968 case 'F': case 'f':
969 memsize = sizeof(float) * data->ssize[i];
970 break;
971 case 'D': case 'd':
972 memsize = sizeof(double) * data->ssize[i];
973 break;
974 case 'C': case 'c':
975 memsize = sizeof(char) * data->ssize[i];
976 break;
977 case 'H': case 'h':
978 memsize = sizeof(short) * data->ssize[i];
979 break;
980 default:
981 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
983 memimg = ary2cary(data->stype[i], val, NULL);
984 memcpy(data->ptr, memimg, memsize);
985 dlfree(memimg);
988 return val;
989 /* break; */
992 rb_raise(rb_eNameError, "undefined key `%s' for %s",
993 rb_id2name(id), rb_class2name(CLASS_OF(self)));
995 return Qnil;
998 VALUE
999 rb_dlptr_size(int argc, VALUE argv[], VALUE self)
1001 VALUE size;
1003 if (rb_scan_args(argc, argv, "01", &size) == 0){
1004 return DLLONG2NUM(RDLPTR(self)->size);
1006 else{
1007 RDLPTR(self)->size = DLNUM2LONG(size);
1008 return size;
1012 static VALUE
1013 dlmem_each_i(VALUE assoc, void *data)
1015 VALUE key, val;
1016 key = rb_ary_entry(assoc, 0);
1017 val = rb_ary_entry(assoc, 1);
1018 rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val)));
1019 return Qnil;
1022 VALUE
1023 rb_dlmem_each(VALUE self)
1025 rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0);
1026 return Qnil;
1029 void
1030 Init_dlptr()
1032 rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cObject);
1033 rb_define_alloc_func(rb_cDLPtrData, rb_dlptr_s_allocate);
1034 rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1);
1035 rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -1);
1036 rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1);
1037 rb_define_method(rb_cDLPtrData, "free", rb_dlptr_free_get, 0);
1038 rb_define_method(rb_cDLPtrData, "to_i", rb_dlptr_to_i, 0);
1039 rb_define_method(rb_cDLPtrData, "ptr", rb_dlptr_ptr, 0);
1040 rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0);
1041 rb_define_method(rb_cDLPtrData, "ref", rb_dlptr_ref, 0);
1042 rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0);
1043 rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0);
1044 rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1);
1045 rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1);
1046 rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1);
1047 rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0);
1048 rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1);
1049 rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1);
1050 rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1);
1051 rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1);
1052 rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1);
1053 rb_define_method(rb_cDLPtrData, "define_data_type",
1054 rb_dlptr_define_data_type, -1);
1055 rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1);
1056 rb_define_method(rb_cDLPtrData, "union!", rb_dlptr_define_union, -1);
1057 rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0);
1058 rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1);
1059 rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1);
1060 rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1);
1061 rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1);
1063 rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace");
1064 DLMemoryTable = rb_hash_new();
1065 rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable);
1066 rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0);