diff options
author | ttate <ttate@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2002-04-02 10:56:13 +0000 |
---|---|---|
committer | ttate <ttate@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2002-04-02 10:56:13 +0000 |
commit | 7d711b817e62eb6c8dee01ea2283fcb1ad90f8ac (patch) | |
tree | b1b54ab76217775071de4e3669674aa7887aa6b9 /ext/dl/ptr.c | |
parent | 64b6406445e53f187d2982f87becff8065edd0cc (diff) |
Add ruby-dl
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2324 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/dl/ptr.c')
-rw-r--r-- | ext/dl/ptr.c | 1075 |
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); +}; |