summaryrefslogtreecommitdiff
path: root/ext/dl/ptr.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/dl/ptr.c')
-rw-r--r--ext/dl/ptr.c1075
1 files changed, 1075 insertions, 0 deletions
diff --git a/ext/dl/ptr.c b/ext/dl/ptr.c
new file mode 100644
index 0000000000..6ac214bc46
--- /dev/null
+++ b/ext/dl/ptr.c
@@ -0,0 +1,1075 @@
+/* -*- C -*-
+ * $Id$
+ */
+
+#include <ruby.h>
+#include <version.h> /* for ruby version code */
+#include "dl.h"
+
+VALUE rb_cDLPtrData;
+VALUE rb_mDLMemorySpace;
+static VALUE DLMemoryTable;
+
+#ifndef T_SYMBOL
+# define T_SYMBOL T_FIXNUM
+#endif
+
+#if RUBY_VERSION_CODE < 171
+static VALUE
+rb_hash_delete(VALUE hash, VALUE key)
+{
+ return rb_funcall(hash, rb_intern("delete"), 1, key);
+}
+#endif
+
+static void
+rb_dlmem_delete(void *ptr)
+{
+ rb_hash_delete(DLMemoryTable, DLLONG2NUM(ptr));
+};
+
+static void
+rb_dlmem_aset(void *ptr, VALUE obj)
+{
+ if( obj == Qnil ){
+ rb_dlmem_delete(ptr);
+ }
+ else{
+ rb_hash_aset(DLMemoryTable, DLLONG2NUM(ptr), DLLONG2NUM(obj));
+ };
+};
+
+static VALUE
+rb_dlmem_aref(void *ptr)
+{
+ VALUE val;
+
+ val = rb_hash_aref(DLMemoryTable, DLLONG2NUM(ptr));
+ return val == Qnil ? Qnil : (VALUE)DLNUM2LONG(val);
+};
+
+void
+dlptr_free(struct ptr_data *data)
+{
+ if( data->ptr ){
+ DEBUG_CODE({
+ printf("dlptr_free(): removing the pointer `0x%x' from the MemorySpace\n",
+ data->ptr);
+ });
+ rb_dlmem_delete(data->ptr);
+ if( data->free ){
+ DEBUG_CODE({
+ printf("dlptr_free(): 0x%x(data->ptr:0x%x)\n",data->free,data->ptr);
+ });
+ (*(data->free))(data->ptr);
+ };
+ };
+ if( data->stype ) dlfree(data->stype);
+ if( data->ssize ) dlfree(data->ssize);
+ if( data->ids ) dlfree(data->ids);
+};
+
+void
+dlptr_init(VALUE val)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(val, struct ptr_data, data);
+ DEBUG_CODE({
+ printf("dlptr_init(): add the pointer `0x%x' to the MemorySpace\n",
+ data->ptr);
+ });
+ rb_dlmem_aset(data->ptr, val);
+};
+
+VALUE
+rb_dlptr_new(void *ptr, long size, freefunc_t func)
+{
+ struct ptr_data *data;
+ VALUE val;
+
+ if( ptr ){
+ val = rb_dlmem_aref(ptr);
+ if( val == Qnil ){
+ val = Data_Make_Struct(rb_cDLPtrData, struct ptr_data,
+ 0, dlptr_free, data);
+ data->ptr = ptr;
+ data->free = func;
+ data->ctype = DLPTR_CTYPE_UNKNOWN;
+ data->stype = NULL;
+ data->ssize = NULL;
+ data->slen = 0;
+ data->size = size;
+ data->ids = NULL;
+ data->ids_num = 0;
+ dlptr_init(val);
+ }
+ else{
+ if( func ){
+ Data_Get_Struct(val, struct ptr_data, data);
+ data->free = func;
+ };
+ };
+ }
+ else{
+ val = Qnil;
+ };
+
+ return val;
+};
+
+VALUE
+rb_dlptr_alloc(long size, freefunc_t func)
+{
+ return rb_dlptr_new(dlmalloc((size_t)size), size, func);
+};
+
+void *
+rb_dlptr2cptr(VALUE val)
+{
+ struct ptr_data *data;
+ void *ptr;
+
+ if( rb_obj_is_kind_of(val, rb_cDLPtrData) ){
+ Data_Get_Struct(val, struct ptr_data, data);
+ ptr = data->ptr;
+ }
+ else if( val == Qnil ){
+ ptr = NULL;
+ }
+ else{
+ rb_raise(rb_eTypeError, "DL::PtrData was expected");
+ };
+
+ return ptr;
+};
+
+static VALUE
+rb_dlptr_s_new(int argc, VALUE argv[], VALUE klass)
+{
+ VALUE ptr, sym, obj, size;
+ void *p = NULL;
+ void (*f)() = NULL;
+ long s = 0;
+
+ switch( rb_scan_args(argc, argv, "12", &ptr, &size, &sym) ){
+ case 1:
+ p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
+ break;
+ case 2:
+ p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
+ s = DLNUM2LONG(size);
+ break;
+ case 3:
+ p = (void*)(DLNUM2LONG(rb_Integer(ptr)));
+ s = DLNUM2LONG(size);
+ f = rb_dlsym2csym(sym);
+ break;
+ default:
+ rb_bug("rb_dlptr_s_new");
+ };
+
+ obj = rb_dlptr_new(p,s,f);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+};
+
+static VALUE
+rb_dlptr_s_alloc(int argc, VALUE argv[], VALUE klass)
+{
+ VALUE size, sym, obj;
+ int s;
+ void (*f)() = NULL;
+
+ switch( rb_scan_args(argc, argv, "11", &size, &sym) ){
+ case 1:
+ s = NUM2INT(size);
+ break;
+ case 2:
+ s = NUM2INT(size);
+ f = rb_dlsym2csym(sym);
+ break;
+ default:
+ rb_bug("rb_dlptr_s_new");
+ };
+
+ obj = rb_dlptr_alloc(s,f);
+
+ rb_obj_call_init(obj, argc, argv);
+
+ return obj;
+};
+
+static VALUE
+rb_dlptr_init(int argc, VALUE argv[], VALUE self)
+{
+ return Qnil;
+};
+
+static VALUE
+rb_dlptr_cast(int argc, VALUE argv[], VALUE self)
+{
+ VALUE klass, rest, val, *pass_argv;
+ int pass_argc, i;
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ rb_scan_args(argc, argv, "1*", &klass, &rest);
+
+ /* prepare the arguments of `new' method */
+ pass_argc = argc + 1;
+ pass_argv = ALLOCA_N(VALUE, pass_argc);
+ pass_argv[0] = DLLONG2NUM(data->ptr);
+ pass_argv[1] = rb_dlsym_new(data->free, NULL, NULL);
+ for( i=2; i < pass_argc; i++ ){
+ pass_argv[i] = rb_ary_entry(rest,i-2);
+ };
+
+ /* remove the data */
+ ((struct ptr_data *)(RDATA(self)->data))->ptr = 0;
+ (RDATA(self)->dfree)(RDATA(self)->data);
+
+ /* call the `new' method of klass with prepared arguments */
+ val = rb_funcall2(klass, rb_intern("new"), pass_argc, pass_argv);
+
+ RDATA(self)->basic.klass = RDATA(val)->basic.klass;
+ RDATA(self)->basic.flags = RDATA(val)->basic.flags;
+ RDATA(self)->dmark = RDATA(val)->dmark;
+ RDATA(self)->dfree = RDATA(val)->dfree;
+ RDATA(self)->data = RDATA(val)->data;
+
+ RDATA(val)->dmark = 0;
+ RDATA(val)->dfree = 0;
+
+ return Qnil;
+};
+
+VALUE
+rb_dlptr_to_i(VALUE self)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ return DLLONG2NUM(data->ptr);
+};
+
+VALUE
+rb_dlptr_ptr(VALUE self)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ return rb_dlptr_new(*((void**)(data->ptr)),0,0);
+};
+
+VALUE
+rb_dlptr_ref(VALUE self)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ return rb_dlptr_new(&(data->ptr),0,0);
+};
+
+VALUE
+rb_dlptr_null_p(VALUE self)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ return data->ptr ? Qfalse : Qtrue;
+};
+
+VALUE
+rb_dlptr_free_set(VALUE self, VALUE val)
+{
+ struct ptr_data *data;
+ int i;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+
+ data->free = DLFREEFUNC(rb_dlsym2csym(val));
+
+ return Qnil;
+};
+
+VALUE
+rb_dlptr_free_get(VALUE self)
+{
+ struct ptr_data *pdata;
+
+ Data_Get_Struct(self, struct ptr_data, pdata);
+
+ return rb_dlsym_new(pdata->free,"(free)","0P");
+};
+
+VALUE
+rb_dlptr_to_array(int argc, VALUE argv[], VALUE self)
+{
+ struct ptr_data *data;
+ int n;
+ int i;
+ int t;
+ VALUE ary;
+ VALUE type, size;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+
+ switch( rb_scan_args(argc, argv, "11", &type, &size) ){
+ case 2:
+ t = STR2CSTR(type)[0];
+ n = NUM2INT(size);
+ break;
+ case 1:
+ t = STR2CSTR(type)[0];
+ switch( t ){
+ case 'C':
+ n = data->size;
+ break;
+ case 'H':
+ n = data->size / sizeof(short);
+ break;
+ case 'I':
+ n = data->size / sizeof(int);
+ break;
+ case 'L':
+ n = data->size / sizeof(long);
+ break;
+ case 'F':
+ n = data->size / sizeof(float);
+ break;
+ case 'D':
+ n = data->size / sizeof(double);
+ break;
+ case 'S': case 'P':
+ n = data->size / sizeof(void*);
+ break;
+ default:
+ if( t == 'p' || t == 's' ){
+ int i;
+ for( i=0; ((void**)(data->ptr))[i]; i++ ){};
+ n = i;
+ }
+ else{
+ n = 0;
+ };
+ };
+ break;
+ default:
+ rb_bug("rb_dlptr_to_array");
+ };
+
+ ary = rb_ary_new();
+
+ for( i=0; i < n; i++ ){
+ switch( t ){
+ case 'C':
+ rb_ary_push(ary, INT2NUM(((char*)(data->ptr))[i]));
+ break;
+ case 'H':
+ rb_ary_push(ary, INT2NUM(((short*)(data->ptr))[i]));
+ break;
+ case 'I':
+ rb_ary_push(ary, INT2NUM(((int*)(data->ptr))[i]));
+ break;
+ case 'L':
+ rb_ary_push(ary, DLLONG2NUM(((long*)(data->ptr))[i]));
+ break;
+ case 'D':
+ rb_ary_push(ary, rb_float_new(((double*)(data->ptr))[i]));
+ case 'F':
+ rb_ary_push(ary, rb_float_new(((float*)(data->ptr))[i]));
+ break;
+ case 'S':
+ {
+ char *str = ((char**)(data->ptr))[i];
+ if( str ){
+ rb_ary_push(ary, rb_tainted_str_new2(str));
+ }
+ else{
+ rb_ary_push(ary, Qnil);
+ };
+ };
+ break;
+ case 's':
+ {
+ char *str = ((char**)(data->ptr))[i];
+ if( str ){
+ rb_ary_push(ary, rb_tainted_str_new2(str));
+ xfree(str);
+ }
+ else{
+ rb_ary_push(ary, Qnil);
+ };
+ };
+ break;
+ case 'P':
+ rb_ary_push(ary, rb_dlptr_new(((void**)(data->ptr))[i],0,0));
+ break;
+ case 'p':
+ rb_ary_push(ary,
+ rb_dlptr_new(((void**)(data->ptr))[i],0,dlfree));
+ break;
+ };
+ };
+
+ return ary;
+};
+
+
+VALUE
+rb_dlptr_to_s(int argc, VALUE argv[], VALUE self)
+{
+ struct ptr_data *data;
+ VALUE arg1, val;
+ int len;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ switch( rb_scan_args(argc, argv, "01", &arg1) ){
+ case 0:
+ val = rb_tainted_str_new2((char*)(data->ptr));
+ break;
+ case 1:
+ len = NUM2INT(arg1);
+ val = rb_tainted_str_new((char*)(data->ptr), len);
+ break;
+ default:
+ rb_bug("rb_dlptr_to_s");
+ };
+
+ return val;
+};
+
+VALUE
+rb_dlptr_to_str(int argc, VALUE argv[], VALUE self)
+{
+ struct ptr_data *data;
+ VALUE arg1, val;
+ int len;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ switch( rb_scan_args(argc, argv, "01", &arg1) ){
+ case 0:
+ val = rb_tainted_str_new((char*)(data->ptr),data->size);
+ break;
+ case 1:
+ len = NUM2INT(arg1);
+ val = rb_tainted_str_new((char*)(data->ptr), len);
+ break;
+ default:
+ rb_bug("rb_dlptr_to_str");
+ };
+
+ return val;
+};
+
+VALUE
+rb_dlptr_inspect(VALUE self)
+{
+ struct ptr_data *data;
+ char str[1024];
+ VALUE name;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ snprintf(str, 1023, "#<%s:0x%x ptr=0x%x size=%ld free=0x%x>",
+ rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, data->free);
+ return rb_str_new2(str);
+};
+
+VALUE
+rb_dlptr_eql(VALUE self, VALUE other)
+{
+ void *ptr1, *ptr2;
+ ptr1 = rb_dlptr2cptr(self);
+ ptr2 = rb_dlptr2cptr(other);
+
+ return ptr1 == ptr2 ? Qtrue : Qfalse;
+};
+
+VALUE
+rb_dlptr_cmp(VALUE self, VALUE other)
+{
+ void *ptr1, *ptr2;
+ ptr1 = rb_dlptr2cptr(self);
+ ptr2 = rb_dlptr2cptr(other);
+ return DLLONG2NUM((long)ptr1 - (long)ptr2);
+};
+
+VALUE
+rb_dlptr_plus(VALUE self, VALUE other)
+{
+ void *ptr;
+ long num, size;
+
+ ptr = rb_dlptr2cptr(self);
+ size = RDLPTR(self)->size;
+ num = DLNUM2LONG(other);
+ return rb_dlptr_new((void*)(ptr + num), size - num, 0);
+};
+
+VALUE
+rb_dlptr_minus(VALUE self, VALUE other)
+{
+ void *ptr;
+ long num, size;
+
+ ptr = rb_dlptr2cptr(self);
+ size = RDLPTR(self)->size;
+ num = DLNUM2LONG(other);
+ return rb_dlptr_new((void*)(ptr - num), size + num, 0);
+};
+
+VALUE
+rb_dlptr_define_data_type(int argc, VALUE argv[], VALUE self)
+{
+ VALUE data_type, type, rest, vid;
+ struct ptr_data *data;
+ int i, t, len, num;
+ char *ctype;
+ long size;
+
+ rb_scan_args(argc, argv, "11*", &data_type, &type, &rest);
+ Data_Get_Struct(self, struct ptr_data, data);
+
+ if( argc == 1 || (argc == 2 && type == Qnil) ){
+ if( NUM2INT(data_type) == DLPTR_CTYPE_UNKNOWN ){
+ data->ctype = DLPTR_CTYPE_UNKNOWN;
+ data->slen = 0;
+ data->ids_num = 0;
+ if( data->stype ){
+ dlfree(data->stype);
+ data->stype = NULL;
+ };
+ if( data->ids ){
+ dlfree(data->ids);
+ data->ids = NULL;
+ };
+ return Qnil;
+ }
+ else{
+ raise(rb_eArgError, "wrong arguments");
+ };
+ };
+
+ Check_Type(data_type, T_FIXNUM);
+ Check_Type(type, T_STRING);
+ Check_Type(rest, T_ARRAY);
+ t = FIX2INT(data_type);
+ num = RARRAY(rest)->len;
+ for( i=0; i<num; i++ ){
+ vid = rb_ary_entry(rest,i);
+ if( !(TYPE(vid)==T_STRING || TYPE(vid)==T_SYMBOL) ){
+ rb_raise(rb_eTypeError, "#%d must be a string or symbol", i + 2);
+ };
+ };
+
+ data->ctype = t;
+ data->slen = num;
+ data->ids_num = num;
+ if( data->stype ) dlfree(data->stype);
+ data->stype = (char*)dlmalloc(sizeof(char) * num);
+ if( data->ssize ) dlfree(data->ssize);
+ data->ssize = (int*)dlmalloc(sizeof(int) * num);
+ if( data->ids ) dlfree(data->ids);
+ data->ids = (ID*)dlmalloc(sizeof(ID) * data->ids_num);
+
+ ctype = STR2CSTR(type);
+ for( i=0; i<num; i++ ){
+ vid = rb_ary_entry(rest,i);
+ data->ids[i] = rb_to_id(vid);
+ data->stype[i] = *ctype;
+ ctype ++;
+ if( isdigit(*ctype) ){
+ char *p, *d;
+ for( p=ctype; isdigit(*p); p++ ) ;
+ d = ALLOCA_N(char, p - ctype + 1);
+ strncpy(d, ctype, p - ctype);
+ d[p - ctype] = '\0';
+ data->ssize[i] = atoi(d);
+ ctype = p;
+ }
+ else{
+ data->ssize[i] = 1;
+ };
+ };
+
+ if( *ctype ){
+ rb_raise(rb_eArgError, "too few/many arguments");
+ };
+
+ if( !data->size )
+ data->size = dlsizeof(STR2CSTR(type));
+
+ return Qnil;
+};
+
+VALUE
+rb_dlptr_define_struct(int argc, VALUE argv[], VALUE self)
+{
+ VALUE *pass_argv;
+ int pass_argc, i;
+
+ pass_argc = argc + 1;
+ pass_argv = ALLOCA_N(VALUE, pass_argc);
+ pass_argv[0] = INT2FIX(DLPTR_CTYPE_STRUCT);
+ for( i=1; i<pass_argc; i++ ){
+ pass_argv[i] = argv[i-1];
+ };
+ return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
+};
+
+VALUE
+rb_dlptr_define_union(int argc, VALUE argv[], VALUE self)
+{
+ VALUE *pass_argv;
+ int pass_argc, i;
+
+ pass_argc = argc + 1;
+ pass_argv = ALLOCA_N(VALUE, pass_argc);
+ pass_argv[0] = INT2FIX(DLPTR_CTYPE_UNION);
+ for( i=1; i<pass_argc; i++ ){
+ pass_argv[i] = argv[i-1];
+ };
+ return rb_dlptr_define_data_type(pass_argc, pass_argv, self);
+};
+
+VALUE
+rb_dlptr_get_data_type(VALUE self)
+{
+ struct ptr_data *data;
+
+ Data_Get_Struct(self, struct ptr_data, data);
+ if( data->stype )
+ return rb_assoc_new(INT2FIX(data->ctype),
+ rb_tainted_str_new(data->stype, data->slen));
+ else
+ return rb_assoc_new(INT2FIX(data->ctype), Qnil);
+};
+
+static VALUE
+cary2ary(void *ptr, char t, int len)
+{
+ VALUE ary;
+ VALUE elem;
+ int i;
+
+ if( len < 1 )
+ return Qnil;
+
+ if( len == 1 ){
+ switch( t ){
+ case 'I': case 'i':
+ elem = INT2NUM(*((int*)ptr));
+ ptr += sizeof(int);
+ break;
+ case 'L': case 'l':
+ elem = DLLONG2NUM(*((long*)ptr));
+ ptr += sizeof(long);
+ break;
+ case 'P': case 'p':
+ elem = rb_dlptr_new(*((void**)ptr),0, 0);
+ ptr += sizeof(void*);
+ break;
+ case 'F': case 'f':
+ elem = rb_float_new(*((float*)ptr));
+ ptr += sizeof(float);
+ break;
+ case 'D': case 'd':
+ elem = rb_float_new(*((float*)ptr));
+ ptr += sizeof(double);
+ break;
+ case 'C': case 'c':
+ elem = INT2NUM(*((char*)ptr));
+ ptr += sizeof(char);
+ break;
+ case 'H': case 'h':
+ elem = INT2NUM(*((short*)ptr));
+ ptr += sizeof(short);
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", t);
+ };
+ return elem;
+ };
+
+ ary = rb_ary_new();
+ for( i=0; i < len; i++ ){
+ switch( t ){
+ case 'I': case 'i':
+ elem = INT2NUM(*((int*)ptr));
+ ptr += sizeof(int);
+ break;
+ case 'L': case 'l':
+ elem = DLLONG2NUM(*((long*)ptr));
+ ptr += sizeof(long);
+ break;
+ case 'P': case 'p':
+ elem = rb_dlptr_new(*((void**)ptr), 0, 0);
+ ptr += sizeof(void*);
+ break;
+ case 'F': case 'f':
+ elem = rb_float_new(*((float*)ptr));
+ ptr += sizeof(float);
+ break;
+ case 'D': case 'd':
+ elem = rb_float_new(*((float*)ptr));
+ ptr += sizeof(double);
+ break;
+ case 'C': case 'c':
+ elem = INT2NUM(*((char*)ptr));
+ ptr += sizeof(char);
+ break;
+ case 'H': case 'h':
+ elem = INT2NUM(*((short*)ptr));
+ ptr += sizeof(short);
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", t);
+ };
+ rb_ary_push(ary, elem);
+ };
+
+ return ary;
+};
+
+VALUE
+rb_dlptr_aref(int argc, VALUE argv[], VALUE self)
+{
+ VALUE val, key = Qnil, num = Qnil;
+ ID id;
+ int idx;
+ struct ptr_data *data;
+ int i;
+ int offset;
+
+ if( rb_scan_args(argc, argv, "11", &key, &num) == 1 ){
+ num = INT2NUM(0);
+ };
+
+ if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
+ VALUE pass[] = {num};
+ return rb_dlptr_to_str(1, pass, rb_dlptr_plus(self, key));
+ };
+
+ if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
+ rb_raise(rb_eTypeError, "the key must be a string or symbol");
+ };
+
+ id = rb_to_id(key);
+ Data_Get_Struct(self, struct ptr_data, data);
+ switch( data->ctype ){
+ case DLPTR_CTYPE_STRUCT:
+ offset = 0;
+ for( i=0; i < data->ids_num; i++ ){
+ if( data->ids[i] == id ){
+ switch( data->stype[i] ){
+ case 'I':
+ DLALIGN(data->ptr,offset,INT_ALIGN);
+ break;
+ case 'L':
+ DLALIGN(data->ptr,offset,LONG_ALIGN);
+ break;
+ case 'P':
+ DLALIGN(data->ptr,offset,VOIDP_ALIGN);
+ case 'F':
+ DLALIGN(data->ptr,offset,FLOAT_ALIGN);
+ break;
+ case 'D':
+ DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
+ break;
+ case 'C':
+ break;
+ case 'H':
+ DLALIGN(data->ptr,offset,SHORT_ALIGN);
+ break;
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
+ };
+ return cary2ary(data->ptr + offset, data->stype[i], data->ssize[i]);
+ };
+ switch( data->stype[i] ){
+ case 'I':
+ case 'i':
+ offset += sizeof(int) * data->ssize[i];
+ break;
+ case 'L':
+ case 'l':
+ offset += sizeof(long) * data->ssize[i];
+ break;
+ case 'P':
+ case 'p':
+ offset += sizeof(void*) * data->ssize[i];
+ break;
+ case 'F':
+ case 'f':
+ offset += sizeof(float) * data->ssize[i];
+ break;
+ case 'D':
+ case 'd':
+ offset += sizeof(double) * data->ssize[i];
+ break;
+ case 'C':
+ case 'c':
+ offset += sizeof(char) * data->ssize[i];
+ break;
+ case 'H':
+ case 'h':
+ offset += sizeof(short) * data->ssize[i];
+ break;
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
+ };
+ };
+ break;
+ case DLPTR_CTYPE_UNION:
+ for( i=0; i < data->ids_num; i++ ){
+ if( data->ids[i] == id ){
+ return cary2ary(data->ptr + offset, data->stype[i], data->ssize[i]);
+ };
+ };
+ break;
+ }; /* end of switch */
+
+ rb_raise(rb_eNameError, "undefined key `%s' for %s",
+ rb_id2name(id), rb_class2name(CLASS_OF(self)));
+
+ return Qnil;
+};
+
+static void *
+ary2cary(char t, VALUE val, long *size)
+{
+ void *ptr;
+
+ if( TYPE(val) == T_ARRAY ){
+ ptr = rb_ary2cary(t, val, size);
+ }
+ else{
+ ptr = rb_ary2cary(t, rb_ary_new3(1, val), size);
+ };
+ return ptr;
+};
+
+VALUE
+rb_dlptr_aset(int argc, VALUE argv[], VALUE self)
+{
+ VALUE key = Qnil, num = Qnil, val = Qnil;
+ ID id;
+ struct ptr_data *data;
+ int i;
+ int offset;
+ long memsize;
+ void *memimg;
+
+ switch( rb_scan_args(argc, argv, "21", &key, &num, &val) ){
+ case 2:
+ val = num;
+ num = Qnil;
+ break;
+ };
+
+ if( TYPE(key) == T_FIXNUM || TYPE(key) == T_BIGNUM ){
+ void *dst, *src;
+ int len;
+
+ Check_Type(val, T_STRING);
+ Data_Get_Struct(self, struct ptr_data, data);
+ dst = (void*)((long)(data->ptr) + DLNUM2LONG(key));
+ src = STR2CSTR(val);
+ if( num == Qnil ){
+ len = RSTRING(val)->len;
+ }
+ else{
+ len = NUM2INT(num);
+ };
+ memcpy(dst, src, len);
+ return val;
+ };
+
+ if( ! (TYPE(key) == T_STRING || TYPE(key) == T_SYMBOL ) ){
+ rb_raise(rb_eTypeError, "the key must be a string or symbol");
+ };
+
+ id = rb_to_id(key);
+ Data_Get_Struct(self, struct ptr_data, data);
+ switch( data->ctype ){
+ case DLPTR_CTYPE_STRUCT:
+ offset = 0;
+ for( i=0; i < data->ids_num; i++ ){
+ if( data->ids[i] == id ){
+ switch( data->stype[i] ){
+ case 'I':
+ DLALIGN(data->ptr,offset,INT_ALIGN);
+ break;
+ case 'L':
+ DLALIGN(data->ptr,offset,LONG_ALIGN);
+ break;
+ case 'P':
+ DLALIGN(data->ptr,offset,VOIDP_ALIGN);
+ break;
+ case 'D':
+ DLALIGN(data->ptr,offset,DOUBLE_ALIGN);
+ break;
+ case 'F':
+ DLALIGN(data->ptr,offset,FLOAT_ALIGN);
+ break;
+ case 'C':
+ break;
+ case 'H':
+ DLALIGN(data->ptr,offset,SHORT_ALIGN);
+ break;
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
+ };
+ memimg = ary2cary(data->stype[i], val, &memsize);
+ memcpy(data->ptr + offset, memimg, memsize);
+ return val;
+ };
+ switch( data->stype[i] ){
+ case 'I':
+ case 'i':
+ offset += sizeof(int) * data->ssize[i];
+ break;
+ case 'L':
+ case 'l':
+ offset += sizeof(long) * data->ssize[i];
+ break;
+ case 'P':
+ case 'p':
+ offset += sizeof(void*) * data->ssize[i];
+ break;
+ case 'D':
+ case 'd':
+ offset += sizeof(double) * data->ssize[i];
+ break;
+ case 'F':
+ case 'f':
+ offset += sizeof(float) * data->ssize[i];
+ break;
+ case 'C':
+ case 'c':
+ offset += sizeof(char) * data->ssize[i];
+ break;
+ case 'H':
+ case 'h':
+ offset += sizeof(short) * data->ssize[i];
+ break;
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
+ };
+ };
+ return val;
+ /* break; */
+ case DLPTR_CTYPE_UNION:
+ for( i=0; i < data->ids_num; i++ ){
+ if( data->ids[i] == id ){
+ switch( data->stype[i] ){
+ case 'I': case 'i':
+ memsize = sizeof(int) * data->ssize[i];
+ break;
+ case 'L': case 'l':
+ memsize = sizeof(long) * data->ssize[i];
+ break;
+ case 'P': case 'p':
+ memsize = sizeof(void*) * data->ssize[i];
+ break;
+ case 'F': case 'f':
+ memsize = sizeof(float) * data->ssize[i];
+ break;
+ case 'D': case 'd':
+ memsize = sizeof(double) * data->ssize[i];
+ break;
+ case 'C': case 'c':
+ memsize = sizeof(char) * data->ssize[i];
+ break;
+ case 'H': case 'h':
+ memsize = sizeof(short) * data->ssize[i];
+ break;
+ default:
+ raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]);
+ };
+ memimg = ary2cary(data->stype[i], val, NULL);
+ memcpy(data->ptr, memimg, memsize);
+ };
+ };
+ return val;
+ /* break; */
+ };
+
+ rb_raise(rb_eNameError, "undefined key `%s' for %s",
+ rb_id2name(id), rb_class2name(CLASS_OF(self)));
+
+ return Qnil;
+};
+
+VALUE
+rb_dlptr_size(int argc, VALUE argv[], VALUE self)
+{
+ VALUE size;
+
+ switch( rb_scan_args(argc, argv, "01", &size) ){
+ case 0:
+ return DLLONG2NUM(RDLPTR(self)->size);
+ case 1:
+ RDLPTR(self)->size = DLNUM2LONG(size);
+ return size;
+ };
+};
+
+static VALUE
+dlmem_each_i(VALUE assoc, void *data)
+{
+ VALUE key, val;
+ key = rb_ary_entry(assoc, 0);
+ val = rb_ary_entry(assoc, 1);
+ rb_yield(rb_assoc_new(key,(VALUE)DLNUM2LONG(val)));
+ return Qnil;
+};
+
+VALUE
+rb_dlmem_each(VALUE self)
+{
+ rb_iterate(rb_each, DLMemoryTable, dlmem_each_i, 0);
+ return Qnil;
+};
+
+void
+Init_dlptr()
+{
+ rb_cDLPtrData = rb_define_class_under(rb_mDL, "PtrData", rb_cData);
+ rb_define_singleton_method(rb_cDLPtrData, "new", rb_dlptr_s_new, -1);
+ rb_define_singleton_method(rb_cDLPtrData, "alloc", rb_dlptr_s_alloc, -1);
+ rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_init, -1);
+ rb_define_method(rb_cDLPtrData, "free=", rb_dlptr_free_set, 1);
+ rb_define_method(rb_cDLPtrData, "free", rb_dlptr_free_get, 0);
+ rb_define_method(rb_cDLPtrData, "to_i", rb_dlptr_to_i, 0);
+ rb_define_method(rb_cDLPtrData, "ptr", rb_dlptr_ptr, 0);
+ rb_define_method(rb_cDLPtrData, "+@", rb_dlptr_ptr, 0);
+ rb_define_method(rb_cDLPtrData, "ref", rb_dlptr_ref, 0);
+ rb_define_method(rb_cDLPtrData, "-@", rb_dlptr_ref, 0);
+ rb_define_method(rb_cDLPtrData, "null?", rb_dlptr_null_p, 0);
+ rb_define_method(rb_cDLPtrData, "to_a", rb_dlptr_to_array, -1);
+ rb_define_method(rb_cDLPtrData, "to_s", rb_dlptr_to_s, -1);
+ rb_define_method(rb_cDLPtrData, "to_str", rb_dlptr_to_str, -1);
+ rb_define_method(rb_cDLPtrData, "inspect", rb_dlptr_inspect, 0);
+ rb_define_method(rb_cDLPtrData, "<=>", rb_dlptr_cmp, 1);
+ rb_define_method(rb_cDLPtrData, "==", rb_dlptr_eql, 1);
+ rb_define_method(rb_cDLPtrData, "eql?", rb_dlptr_eql, 1);
+ rb_define_method(rb_cDLPtrData, "+", rb_dlptr_plus, 1);
+ rb_define_method(rb_cDLPtrData, "-", rb_dlptr_minus, 1);
+ rb_define_method(rb_cDLPtrData, "cast!", rb_dlptr_cast, -1);
+ rb_define_method(rb_cDLPtrData, "define_data_type",
+ rb_dlptr_define_data_type, -1);
+ rb_define_method(rb_cDLPtrData, "struct!", rb_dlptr_define_struct, -1);
+ rb_define_method(rb_cDLPtrData, "union!", rb_dlptr_define_union, -1);
+ rb_define_method(rb_cDLPtrData, "data_type", rb_dlptr_get_data_type, 0);
+ rb_define_method(rb_cDLPtrData, "[]", rb_dlptr_aref, -1);
+ rb_define_method(rb_cDLPtrData, "[]=", rb_dlptr_aset, -1);
+ rb_define_method(rb_cDLPtrData, "size", rb_dlptr_size, -1);
+ rb_define_method(rb_cDLPtrData, "size=", rb_dlptr_size, -1);
+
+ rb_mDLMemorySpace = rb_define_module_under(rb_mDL, "MemorySpace");
+ DLMemoryTable = rb_hash_new();
+ rb_define_const(rb_mDLMemorySpace, "MemoryTable", DLMemoryTable);
+ rb_define_module_function(rb_mDLMemorySpace, "each", rb_dlmem_each, 0);
+};