DEFINITIONS
This source file includes following functions.
- rb_hash_delete
- rb_dlmem_delete
- rb_dlmem_aset
- rb_dlmem_aref
- dlptr_free
- dlptr_init
- rb_dlptr_new2
- rb_dlptr_new
- rb_dlptr_malloc
- rb_dlptr2cptr
- rb_dlptr_s_allocate
- rb_dlptr_initialize
- rb_dlptr_s_malloc
- rb_dlptr_to_i
- rb_dlptr_ptr
- rb_dlptr_ref
- rb_dlptr_null_p
- rb_dlptr_free_set
- rb_dlptr_free_get
- rb_dlptr_to_array
- rb_dlptr_to_s
- rb_dlptr_to_str
- rb_dlptr_inspect
- rb_dlptr_eql
- rb_dlptr_cmp
- rb_dlptr_plus
- rb_dlptr_minus
- rb_dlptr_define_data_type
- rb_dlptr_define_struct
- rb_dlptr_define_union
- rb_dlptr_get_data_type
- cary2ary
- rb_dlptr_aref
- ary2cary
- rb_dlptr_aset
- rb_dlptr_size
- dlmem_each_i
- rb_dlmem_each
- Init_dlptr
1
2
3
4
5 #include <ruby.h>
6 #include <version.h>
7 #include "dl.h"
8
9 VALUE rb_cDLPtrData;
10 VALUE rb_mDLMemorySpace;
11 static VALUE DLMemoryTable;
12
13 #ifndef T_SYMBOL
14 # define T_SYMBOL T_FIXNUM
15 #endif
16
17 #if RUBY_VERSION_CODE < 171
18 static VALUE
19 rb_hash_delete(VALUE hash, VALUE key)
20 {
21 return rb_funcall(hash, rb_intern("delete"), 1, key);
22 }
23 #endif
24
25 static void
26 rb_dlmem_delete(void *ptr)
27 {
28 rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr));
29 }
30
31 static void
32 rb_dlmem_aset(void *ptr, VALUE obj)
33 {
34 if( obj == Qnil ){
35 rb_dlmem_delete(ptr);
36 }
37 else{
38 rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj));
39 };
40 }
41
42 static VALUE
43 rb_dlmem_aref(void *ptr)
44 {
45 VALUE val;
46
47 val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr));
48 return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val);
49 }
50
51 void
52 dlptr_free(struct ptr_data *data)
53 {
54 if( data->ptr ){
55 DEBUG_CODE({
56 printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n",
57 data->ptr);
58 });
59 rb_dlmem_delete(data->ptr);
60 if( data->free ){
61 DEBUG_CODE({
62 printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr);
63 });
64 (*(data->free))(data->ptr);
65 };
66 };
67 if( data->stype ) dlfree(data->stype);
68 if( data->ssize ) dlfree(data->ssize);
69 if( data->ids ) dlfree(data->ids);
70 }
71
72 void
73 dlptr_init(VALUE val)
74 {
75 struct ptr_data *data;
76
77 Data_Get_Struct(val, struct ptr_data, data);
78 DEBUG_CODE({
79 printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n",
80 data->ptr);
81 });
82 rb_dlmem_aset(data->ptr, val);
83 }
84
85 VALUE
86 rb_dlptr_new2(VALUE klass, void *ptr, long size, freefunc_t func)
87 {
88 struct ptr_data *data;
89 VALUE val;
90
91 if( ptr ){
92 val = rb_dlmem_aref(ptr);
93 if( val == Qnil ){
94 val = Data_Make_Struct(klass, struct ptr_data,
95 0, dlptr_free, data);
96 data->ptr = ptr;
97 data->free = func;
98 data->ctype = DLPTR_CTYPE_UNKNOWN;
99 data->stype = NULL;
100 data->ssize = NULL;
101 data->slen = 0;
102 data->size = size;
103 data->ids = NULL;
104 data->ids_num = 0;
105 dlptr_init(val);
106 }
107 else{
108 if( func ){
109 Data_Get_Struct(val, struct ptr_data, data);
110 data->free = func;
111 };
112 };
113 }
114 else{
115 val = Qnil;
116 };
117
118 return val;
119 }
120
121 VALUE
122 rb_dlptr_new(void *ptr, long size, freefunc_t func)
123 {
124 return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func);
125 }
126
127 VALUE
128 rb_dlptr_malloc(long size, freefunc_t func)
129 {
130 void *ptr;
131
132 ptr = dlmalloc((size_t)size);
133 memset(ptr,0,(size_t)size);
134 return rb_dlptr_new(ptr, size, func);
135 }
136
137 void *
138 rb_dlptr2cptr(VALUE val)
139 {
140 struct ptr_data *data;
141 void *ptr;
142
143 if( rb_obj_is_kind_of(val, rb_cDLPtrData) ){
144 Data_Get_Struct(val, struct ptr_data, data);
145 ptr = data->ptr;
146 }
147 else if( val == Qnil ){
148 ptr = NULL;
149 }
150 else{
151 rb_raise(rb_eTypeError, "DL::PtrData was expected");
152 };
153
154 return ptr;
155 }
156
157 static VALUE
158 rb_dlptr_s_allocate(VALUE klass)
159 {
160 VALUE obj;
161 struct ptr_data *data;
162
163 obj = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data);
164 data->ptr = 0;
165 data->free = 0;
166 data->ctype = DLPTR_CTYPE_UNKNOWN;
167 data->stype = NULL;
168 data->ssize = NULL;
169 data->slen = 0;
170 data->size = 0;
171 data->ids = NULL;
172 data->ids_num = 0;
173
174 return obj;
175 }
176
177 static VALUE
178 rb_dlptr_initialize(int argc, VALUE argv[], VALUE self)
179 {
180 VALUE ptr, sym, obj, size;
181 struct ptr_data *data;
182 void *p = NULL;
183 freefunc_t f = NULL;
184 long s = 0;
185
186 switch( rb_scan_args(argc, argv, "12", &ptr, &size, &sym) ){
187 case 1:
188 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
189 break;
190 case 2:
191 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
192 s = DLNUM2LONG(size);
193 break;
194 case 3:
195 p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
196 s = DLNUM2LONG(size);
197 f = rb_dlsym2csym(sym);
198 break;
199 default:
200 rb_bug("rb_dlptr_s_new");
201 };
202
203 if( p ){
204 Data_Get_Struct(self, struct ptr_data, data);
205 if( data->ptr && data->free ){
206
207 (*(data->free))(data->ptr);
208 }
209 data->ptr = p;
210 data->size = s;
211 data->free = f;
212 }
213
214 return Qnil;
215 }
216
217 static VALUE
218 rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass)
219 {
220 VALUE size, sym, obj;
221 int s;
222 freefunc_t f = NULL;
223
224 switch( rb_scan_args(argc, argv, "11", &size, &sym) ){
225 case 1:
226 s = NUM2INT(size);
227 break;
228 case 2:
229 s = NUM2INT(size);
230 f = rb_dlsym2csym(sym);
231 break;
232 default:
233 rb_bug("rb_dlptr_s_new");
234 };
235
236 obj = rb_dlptr_malloc(s,f);
237
238 return obj;
239 }
240
241 VALUE
242 rb_dlptr_to_i(VALUE self)
243 {
244 struct ptr_data *data;
245
246 Data_Get_Struct(self, struct ptr_data, data);
247 return DLLONG2NUM(data->ptr);
248 }
249
250 VALUE
251 rb_dlptr_ptr(VALUE self)
252 {
253 struct ptr_data *data;
254
255 Data_Get_Struct(self, struct ptr_data, data);
256 return rb_dlptr_new(*((void**)(data->ptr)),0,0);
257 }
258
259 VALUE
260 rb_dlptr_ref(VALUE self)
261 {
262 struct ptr_data *data;
263
264 Data_Get_Struct(self, struct ptr_data, data);
265 return rb_dlptr_new(&(data->ptr),0,0);
266 }
267
268 VALUE
269 rb_dlptr_null_p(VALUE self)
270 {
271 struct ptr_data *data;
272
273 Data_Get_Struct(self, struct ptr_data, data);
274 return data->ptr ? Qfalse : Qtrue;
275 }
276
277 VALUE
278 rb_dlptr_free_set(VALUE self, VALUE val)
279 {
280 struct ptr_data *data;
281 int i;
282
283 Data_Get_Struct(self, struct ptr_data, data);
284
285 data->free = DLFREEFUNC(rb_dlsym2csym(val));
286
287 return Qnil;
288 }
289
290 VALUE
291 rb_dlptr_free_get(VALUE self)
292 {
293 struct ptr_data *pdata;
294
295 Data_Get_Struct(self, struct ptr_data, pdata);
296
297 return rb_dlsym_new(pdata->free,"(free)","0P");
298 }
299
300 VALUE
301 rb_dlptr_to_array(int argc, VALUE argv[], VALUE self)
302 {
303 struct ptr_data *data;
304 int n;
305 int i;
306 int t;
307 VALUE ary;
308 VALUE type, size;
309
310 Data_Get_Struct(self, struct ptr_data, data);
311
312 switch( rb_scan_args(argc, argv, "11", &type, &size) ){
313 case 2:
314 t = StringValuePtr(type)[0];
315 n = NUM2INT(size);
316 break;
317 case 1:
318 t = StringValuePtr(type)[0];
319 switch( t ){
320 case 'C':
321 n = data->size;
322 break;
323 case 'H':
324 n = data->size / sizeof(short);
325 break;
326 case 'I':
327 n = data->size / sizeof(int);
328 break;
329 case 'L':
330 n = data->size / sizeof(long);
331 break;
332 case 'F':
333 n = data->size / sizeof(float);
334 break;
335 case 'D':
336 n = data->size / sizeof(double);
337 break;
338 case 'S': case 'P':
339 n = data->size / sizeof(void*);
340 break;
341 default:
342 if( t == 'p' || t == 's' ){
343 int i;
344 for( i=0; ((void**)(data->ptr))[i]; i++ ){};
345 n = i;
346 }
347 else{
348 n = 0;
349 };
350 };
351 break;
352 default:
353 rb_bug("rb_dlptr_to_array");
354 };
355
356 ary = rb_ary_new();
357
358 for( i=0; i < n; i++ ){
359 switch( t ){
360 case 'C':
361 rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i]));
362 break;
363 case 'H':
364 rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i]));
365 break;
366 case 'I':
367 rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i]));
368 break;
369 case 'L':
370 rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i]));
371 break;
372 case 'D':
373 rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i]));
374 case 'F':
375 rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i]));
376 break;
377 case 'S':
378 {
379 char *str = ((char**)(data->ptr))[i];
380 if( str ){
381 rb_ary_push(ary, rb_tainted_str_new2(str));
382 }
383 else{
384 rb_ary_push(ary, Qnil);
385 };
386 };
387 break;
388 case 's':
389 {
390 char *str = ((char**)(data->ptr))[i];
391 if( str ){
392 rb_ary_push(ary, rb_tainted_str_new2(str));
393 xfree(str);
394 }
395 else{
396 rb_ary_push(ary, Qnil);
397 };
398 };
399 break;
400 case 'P':
401 rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0));
402 break;
403 case 'p':
404 rb_ary_push(ary,
405 rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree));
406 break;
407 };
408 };
409
410 return ary;
411 }
412
413
414 VALUE
415 rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
416 {
417 struct ptr_data *data;
418 VALUE arg1, val;
419 int len;
420
421 Data_Get_Struct(self, struct ptr_data, data);
422 switch( rb_scan_args(argc, argv, "01", &arg1) ){
423 case 0:
424 val = rb_tainted_str_new2((char*)(data->ptr));
425 break;
426 case 1:
427 len = NUM2INT(arg1);
428 val = rb_tainted_str_new((char*)(data->ptr), len);
429 break;
430 default:
431 rb_bug("rb_dlptr_to_s");
432 };
433
434 return val;
435 }
436
437 VALUE
438 rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
439 {
440 struct ptr_data *data;
441 VALUE arg1, val;
442 int len;
443
444 Data_Get_Struct(self, struct ptr_data, data);
445 switch( rb_scan_args(argc, argv, "01", &arg1) ){
446 case 0:
447 val = rb_tainted_str_new((char*)(data->ptr),data->size);
448 break;
449 case 1:
450 len = NUM2INT(arg1);
451 val = rb_tainted_str_new((char*)(data->ptr), len);
452 break;
453 default:
454 rb_bug("rb_dlptr_to_str");
455 };
456
457 return val;
458 }
459
460 VALUE
461 rb_dlptr_inspect(VALUE self)
462 {
463 struct ptr_data *data;
464 char str[1024];
465 VALUE name;
466
467 Data_Get_Struct(self, struct ptr_data, data);
468 snprintf(str, 1023, "#<%s:0x%x ptr=0x%x size=%ld free=0x%x>",
469 rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, data->free);
470 return rb_str_new2(str);
471 }
472
473 VALUE
474 rb_dlptr_eql(VALUE self, VALUE other)
475 {
476 void *ptr1, *ptr2;
477 ptr1 = rb_dlptr2cptr(self);
478 ptr2 = rb_dlptr2cptr(other);
479
480 return ptr1 == ptr2 ? Qtrue : Qfalse;
481 }
482
483 VALUE
484 rb_dlptr_cmp(VALUE self, VALUE other)
485 {
486 void *ptr1, *ptr2;
487 ptr1 = rb_dlptr2cptr(self);
488 ptr2 = rb_dlptr2cptr(other);
489 return DLLONG2NUM((long)ptr1 - (long)ptr2);
490 }
491
492 VALUE
493 rb_dlptr_plus(VALUE self, VALUE other)
494 {
495 void *ptr;
496 long num, size;
497
498 ptr = rb_dlptr2cptr(self);
499 size = RDLPTR(self)->size;
500 num = DLNUM2LONG(other);
501 return rb_dlptr_new((char *)ptr + num, size - num, 0);
502 }
503
504 VALUE
505 rb_dlptr_minus(VALUE self, VALUE other)
506 {
507 void *ptr;
508 long num, size;
509
510 ptr = rb_dlptr2cptr(self);
511 size = RDLPTR(self)->size;
512 num = DLNUM2LONG(other);
513 return rb_dlptr_new((char *)ptr - num, size + num, 0);
514 }
515
516 VALUE
517 rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self)
518 {
519 VALUE data_type, type, rest, vid;
520 struct ptr_data *data;
521 int i, t, len, num;
522 char *ctype;
523 long size;
524
525 rb_scan_args(argc, argv, "11*", &data_type, &type, &rest);
526 Data_Get_Struct(self, struct ptr_data, data);
527
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;
536 };
537 if( data->ids ){
538 dlfree(data->ids);
539 data->ids = NULL;
540 };
541 return Qnil;
542 }
543 else{
544 rb_raise(rb_eArgError, "wrong arguments");
545 };
546 };
547
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 vid = rb_ary_entry(rest,i);
554 if( !(TYPE(vid)==T_STRING || TYPE(vid)==T_SYMBOL) ){
555 rb_raise(rb_eTypeError, "#%d must be a string or symbol", i + 2);
556 };
557 };
558
559 data->ctype = t;
560 data->slen = num;
561 data->ids_num = num;
562 if( data->stype ) dlfree(data->stype);
563 data->stype = (char*)dlmalloc(sizeof(char) * num);
564 if( data->ssize ) dlfree(data->ssize);
565 data->ssize = (int*)dlmalloc(sizeof(int) * num);
566 if( data->ids ) dlfree(data->ids);
567 data->ids = (ID*)dlmalloc(sizeof(ID) * data->ids_num);
568
569 ctype = StringValuePtr(type);
570 for( i=0; i<num; i++ ){
571 vid = rb_ary_entry(rest,i);
572 data->ids[i] = rb_to_id(vid);
573 data->stype[i] = *ctype;
574 ctype ++;
575 if( isdigit(*ctype) ){
576 char *p, *d;
577 for( p=ctype; isdigit(*p); p++ ) ;
578 d = ALLOCA_N(char, p - ctype + 1);
579 strncpy(d, ctype, p - ctype);
580 d[p - ctype] = '\0';
581 data->ssize[i] = atoi(d);
582 ctype = p;
583 }
584 else{
585 data->ssize[i] = 1;
586 };
587 };
588
589 if( *ctype ){
590 rb_raise(rb_eArgError, "too few/many arguments");
591 };
592
593 if( !data->size )
594 data->size = dlsizeof(RSTRING(type)->ptr);
595
596 return Qnil;
597 }
598
599 VALUE
600 rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self)
601 {
602 VALUE *pass_argv;
603 int pass_argc, i;
604
605 pass_argc = argc + 1;
606 pass_argv = ALLOCA_N(VALUE, pass_argc);
607 pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT);
608 for( i=1; i<pass_argc; i++ ){
609 pass_argv[i] = argv[i-1];
610 };
611 return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
612 }
613
614 VALUE
615 rb_dlptr_define_union(int argc, VALUE argv[], VALUE self)
616 {
617 VALUE *pass_argv;
618 int pass_argc, i;
619
620 pass_argc = argc + 1;
621 pass_argv = ALLOCA_N(VALUE, pass_argc);
622 pass_argv[0] = INT2FIX(DLPTR_CTYPE_UNION);
623 for( i=1; i<pass_argc; i++ ){
624 pass_argv[i] = argv[i-1];
625 };
626 return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
627 }
628
629 VALUE
630 rb_dlptr_get_data_type(VALUE self)
631 {
632 struct ptr_data *data;
633
634 Data_Get_Struct(self, struct ptr_data, data);
635 if( data->stype )
636 return rb_assoc_new(INT2FIX(data->ctype),
637 rb_tainted_str_new(data->stype, data->slen));
638 else
639 return rb_assoc_new(INT2FIX(data->ctype), Qnil);
640 }
641
642 static VALUE
643 cary2ary(void *ptr, char t, int len)
644 {
645 VALUE ary;
646 VALUE elem;
647 int i;
648
649 if( len < 1 )
650 return Qnil;
651
652 if( len == 1 ){
653 switch( t ){
654 case 'I':
655 elem = INT2NUM(*((int*)ptr));
656 ptr = (char *)ptr + sizeof(int);
657 break;
658 case 'L':
659 elem = DLLONG2NUM(*((long*)ptr));
660 ptr = (char *)ptr + sizeof(long);
661 break;
662 case 'P':
663 elem = rb_dlptr_new(*((void**)ptr),0, 0);
664 ptr = (char *)ptr + sizeof(void*);
665 break;
666 case 'F':
667 elem = rb_float_new(*((float*)ptr));
668 ptr = (char *)ptr + sizeof(float);
669 break;
670 case 'D':
671 elem = rb_float_new(*((double*)ptr));
672 ptr = (char *)ptr + sizeof(double);
673 break;
674 case 'C':
675 elem = INT2NUM(*((char*)ptr));
676 ptr = (char *)ptr + sizeof(char);
677 break;
678 case 'H':
679 elem = INT2NUM(*((short*)ptr));
680 ptr = (char *)ptr + sizeof(short);
681 break;
682 default:
683 rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
684 };
685 return elem;
686 };
687
688 ary = rb_ary_new();
689 for( i=0; i < len; i++ ){
690 switch( t ){
691 case 'I':
692 elem = INT2NUM(*((int*)ptr));
693 ptr = (char *)ptr + sizeof(int);
694 break;
695 case 'L':
696 elem = DLLONG2NUM(*((long*)ptr));
697 ptr = (char *)ptr + sizeof(long);
698 break;
699 case 'P':
700 elem = rb_dlptr_new(*((void**)ptr), 0, 0);
701 ptr = (char *)ptr + sizeof(void*);
702 break;
703 case 'F':
704 elem = rb_float_new(*((float*)ptr));
705 ptr = (char *)ptr + sizeof(float);
706 break;
707 case 'D':
708 elem = rb_float_new(*((float*)ptr));
709 ptr = (char *)ptr + sizeof(double);
710 break;
711 case 'C':
712 elem = INT2NUM(*((char*)ptr));
713 ptr = (char *)ptr + sizeof(char);
714 break;
715 case 'H':
716 elem = INT2NUM(*((short*)ptr));
717 ptr = (char *)ptr + sizeof(short);
718 break;
719 default:
720 rb_raise(rb_eDLTypeError, "unsupported type '%c'", t);
721 };
722 rb_ary_push(ary, elem);
723 };
724
725 return ary;
726 }
727
728 VALUE
729 rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
730 {
731 VALUE val, key = Qnil, num = Qnil;
732 ID id;
733 int idx;
734 struct ptr_data *data;
735 int i;
736 int offset;
737
738 if( rb_scan_args(argc, argv, "11", &key, &num) == 1 ){
739 num = INT2NUM(0);
740 };
741
742 if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
743 VALUE pass[1];
744 pass[0] = num;
745 return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key));
746 };
747
748 if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
749 rb_raise(rb_eTypeError, "the key must be a string or symbol");
750 };
751
752 id = rb_to_id(key);
753 Data_Get_Struct(self, struct ptr_data, data);
754 offset = 0;
755 switch( data->ctype ){
756 case DLPTR_CTYPE_STRUCT:
757 for( i=0; i < data->ids_num; i++ ){
758 if( data->ids[i] == id ){
759 switch( data->stype[i] ){
760 case 'I':
761 DLALIGN(data->ptr,offset,INT_ALIGN);
762 break;
763 case 'L':
764 DLALIGN(data->ptr,offset,LONG_ALIGN);
765 break;
766 case 'P':
767 DLALIGN(data->ptr,offset,VOIDP_ALIGN);
768 break;
769 case 'F':
770 DLALIGN(data->ptr,offset,FLOAT_ALIGN);
771 break;
772 case 'D':
773 DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
774 break;
775 case 'C':
776 break;
777 case 'H':
778 DLALIGN(data->ptr,offset,SHORT_ALIGN);
779 break;
780 default:
781 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
782 };
783 return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]);
784 };
785 switch( data->stype[i] ){
786 case 'I':
787 offset += sizeof(int) * data->ssize[i];
788 break;
789 case 'L':
790 offset += sizeof(long) * data->ssize[i];
791 break;
792 case 'P':
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]);
809 };
810 };
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]);
816 };
817 };
818 break;
819 };
820
821 rb_raise(rb_eNameError, "undefined key `%s' for %s",
822 rb_id2name(id), rb_class2name(CLASS_OF(self)));
823
824 return Qnil;
825 }
826
827 static void *
828 ary2cary(char t, VALUE val, long *size)
829 {
830 void *ptr;
831
832 if( TYPE(val) == T_ARRAY ){
833 ptr = rb_ary2cary(t, val, size);
834 }
835 else{
836 ptr = rb_ary2cary(t, rb_ary_new3(1, val), size);
837 };
838 return ptr;
839 }
840
841 VALUE
842 rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
843 {
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;
851
852 switch( rb_scan_args(argc, argv, "21", &key, &num, &val) ){
853 case 2:
854 val = num;
855 num = Qnil;
856 break;
857 };
858
859 if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
860 void *dst, *src;
861 long len;
862
863 StringValue(val);
864 Data_Get_Struct(self, struct ptr_data, data);
865 dst = (void*)((long)(data->ptr) + DLNUM2LONG(key));
866 src = RSTRING(val)->ptr;
867 len = RSTRING(val)->len;
868 if( num == Qnil ){
869 memcpy(dst, src, len);
870 }
871 else{
872 long n = NUM2INT(num);
873 memcpy(dst, src, n < len ? n : len);
874 if( n > len ) MEMZERO((char*)dst + len, char, n - len);
875 };
876 return val;
877 };
878
879 if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
880 rb_raise(rb_eTypeError, "the key must be a string or symbol");
881 };
882
883 id = rb_to_id(key);
884 Data_Get_Struct(self, struct ptr_data, data);
885 switch( data->ctype ){
886 case DLPTR_CTYPE_STRUCT:
887 offset = 0;
888 for( i=0; i < data->ids_num; i++ ){
889 if( data->ids[i] == id ){
890 switch( data->stype[i] ){
891 case 'I':
892 DLALIGN(data->ptr,offset,INT_ALIGN);
893 break;
894 case 'L':
895 DLALIGN(data->ptr,offset,LONG_ALIGN);
896 break;
897 case 'P':
898 DLALIGN(data->ptr,offset,VOIDP_ALIGN);
899 break;
900 case 'D':
901 DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
902 break;
903 case 'F':
904 DLALIGN(data->ptr,offset,FLOAT_ALIGN);
905 break;
906 case 'C':
907 break;
908 case 'H':
909 DLALIGN(data->ptr,offset,SHORT_ALIGN);
910 break;
911 default:
912 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
913 };
914 memimg = ary2cary(data->stype[i], val, &memsize);
915 memcpy((char *)data->ptr + offset, memimg, memsize);
916 return val;
917 };
918 switch( data->stype[i] ){
919 case 'I':
920 case 'i':
921 offset += sizeof(int) * data->ssize[i];
922 break;
923 case 'L':
924 case 'l':
925 offset += sizeof(long) * data->ssize[i];
926 break;
927 case 'P':
928 case 'p':
929 offset += sizeof(void*) * data->ssize[i];
930 break;
931 case 'D':
932 case 'd':
933 offset += sizeof(double) * data->ssize[i];
934 break;
935 case 'F':
936 case 'f':
937 offset += sizeof(float) * data->ssize[i];
938 break;
939 case 'C':
940 case 'c':
941 offset += sizeof(char) * data->ssize[i];
942 break;
943 case 'H':
944 case 'h':
945 offset += sizeof(short) * data->ssize[i];
946 break;
947 default:
948 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
949 };
950 };
951 return val;
952
953 case DLPTR_CTYPE_UNION:
954 for( i=0; i < data->ids_num; i++ ){
955 if( data->ids[i] == id ){
956 switch( data->stype[i] ){
957 case 'I': case 'i':
958 memsize = sizeof(int) * data->ssize[i];
959 break;
960 case 'L': case 'l':
961 memsize = sizeof(long) * data->ssize[i];
962 break;
963 case 'P': case 'p':
964 memsize = sizeof(void*) * data->ssize[i];
965 break;
966 case 'F': case 'f':
967 memsize = sizeof(float) * data->ssize[i];
968 break;
969 case 'D': case 'd':
970 memsize = sizeof(double) * data->ssize[i];
971 break;
972 case 'C': case 'c':
973 memsize = sizeof(char) * data->ssize[i];
974 break;
975 case 'H': case 'h':
976 memsize = sizeof(short) * data->ssize[i];
977 break;
978 default:
979 rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
980 };
981 memimg = ary2cary(data->stype[i], val, NULL);
982 memcpy(data->ptr, memimg, memsize);
983 };
984 };
985 return val;
986
987 };
988
989 rb_raise(rb_eNameError, "undefined key `%s' for %s",
990 rb_id2name(id), rb_class2name(CLASS_OF(self)));
991
992 return Qnil;
993 }
994
995 VALUE
996 rb_dlptr_size(int argc, VALUE argv[], VALUE self)
997 {
998 VALUE size;
999
1000 if( rb_scan_args(argc, argv, "01", &size) == 0){
1001 return DLLONG2NUM(RDLPTR(self)->size);
1002 }
1003 else{
1004 RDLPTR(self)->size = DLNUM2LONG(size);
1005 return size;
1006 };
1007 }
1008
1009 static VALUE
1010 dlmem_each_i(VALUE assoc, void *data)
1011 {
1012 VALUE key, val;
1013 key = rb_ary_entry(assoc, 0);
1014 val = rb_ary_entry(assoc, 1);
1015 rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val)));
1016 return Qnil;
1017 }
1018
1019 VALUE
1020 rb_dlmem_each(VALUE self)
1021 {
1022 rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0);
1023 return Qnil;
1024 }
1025
1026 void
1027 Init_dlptr()
1028 {
1029 rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cObject);
1030 rb_define_singleton_method(rb_cDLPtrData, "allocate", rb_dlptr_s_allocate, 0);
1031 rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1);
1032 rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -1);
1033 rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1);
1034 rb_define_method(rb_cDLPtrData, "free", rb_dlptr_free_get, 0);
1035 rb_define_method(rb_cDLPtrData, "to_i", rb_dlptr_to_i, 0);
1036 rb_define_method(rb_cDLPtrData, "ptr", rb_dlptr_ptr, 0);
1037 rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0);
1038 rb_define_method(rb_cDLPtrData, "ref", rb_dlptr_ref, 0);
1039 rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0);
1040 rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0);
1041 rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1);
1042 rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1);
1043 rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1);
1044 rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0);
1045 rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1);
1046 rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1);
1047 rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1);
1048 rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1);
1049 rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1);
1050 rb_define_method(rb_cDLPtrData, "define_data_type",
1051 rb_dlptr_define_data_type, -1);
1052 rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1);
1053 rb_define_method(rb_cDLPtrData, "union!", rb_dlptr_define_union, -1);
1054 rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0);
1055 rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1);
1056 rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1);
1057 rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1);
1058 rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1);
1059
1060 rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace");
1061 DLMemoryTable = rb_hash_new();
1062 rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable);
1063 rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0);
1064 }