/* -*- C -*- * $Id$ */ #include #include /* 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_new2(VALUE klass, 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(klass, 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_new(void *ptr, long size, freefunc_t func) { return rb_dlptr_new2(rb_cDLPtrData, ptr, size, func); } VALUE rb_dlptr_malloc(long size, freefunc_t func) { void *ptr; ptr = dlmalloc((size_t)size); memset(ptr,0,(size_t)size); return rb_dlptr_new(ptr, 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_allocate(VALUE klass) { VALUE obj; struct ptr_data *data; obj = Data_Make_Struct(klass, struct ptr_data, 0, dlptr_free, data); data->ptr = 0; data->free = 0; data->ctype = DLPTR_CTYPE_UNKNOWN; data->stype = NULL; data->ssize = NULL; data->slen = 0; data->size = 0; data->ids = NULL; data->ids_num = 0; return obj; } static VALUE rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) { VALUE ptr, sym, obj, size; struct ptr_data *data; void *p = NULL; freefunc_t 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_initialize"); } if( p ){ Data_Get_Struct(self, struct ptr_data, data); if( data->ptr && data->free ){ /* Free previous memory. Use of inappropriate initialize may cause SEGV. */ (*(data->free))(data->ptr); } data->ptr = p; data->size = s; data->free = f; } return Qnil; } static VALUE rb_dlptr_s_malloc(int argc, VALUE argv[], VALUE klass) { VALUE size, sym, obj; int s; freefunc_t 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_malloc"); } obj = rb_dlptr_malloc(s,f); return obj; } 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 = StringValuePtr(type)[0]; n = NUM2INT(size); break; case 1: t = StringValuePtr(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((char *)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((char *)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{ rb_raise(rb_eArgError, "wrong arguments"); } } t = NUM2INT(data_type); StringValue(type); Check_Type(rest, T_ARRAY); num = RARRAY(rest)->len; for( i=0; ictype = 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 = StringValuePtr(type); for( i=0; iids[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(RSTRING(type)->ptr); 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; istype ) 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': elem = INT2NUM(*((int*)ptr)); ptr = (char *)ptr + sizeof(int); break; case 'L': elem = DLLONG2NUM(*((long*)ptr)); ptr = (char *)ptr + sizeof(long); break; case 'P': case 'S': elem = rb_dlptr_new(*((void**)ptr),0, 0); ptr = (char *)ptr + sizeof(void*); break; case 'F': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(float); break; case 'D': elem = rb_float_new(*((double*)ptr)); ptr = (char *)ptr + sizeof(double); break; case 'C': elem = INT2NUM(*((char*)ptr)); ptr = (char *)ptr + sizeof(char); break; case 'H': elem = INT2NUM(*((short*)ptr)); ptr = (char *)ptr + sizeof(short); break; default: rb_raise(rb_eDLTypeError, "unsupported type '%c'", t); } return elem; } ary = rb_ary_new(); for( i=0; i < len; i++ ){ switch( t ){ case 'I': elem = INT2NUM(*((int*)ptr)); ptr = (char *)ptr + sizeof(int); break; case 'L': elem = DLLONG2NUM(*((long*)ptr)); ptr = (char *)ptr + sizeof(long); break; case 'P': case 'S': elem = rb_dlptr_new(*((void**)ptr), 0, 0); ptr = (char *)ptr + sizeof(void*); break; case 'F': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(float); break; case 'D': elem = rb_float_new(*((float*)ptr)); ptr = (char *)ptr + sizeof(double); break; case 'C': elem = INT2NUM(*((char*)ptr)); ptr = (char *)ptr + sizeof(char); break; case 'H': elem = INT2NUM(*((short*)ptr)); ptr = (char *)ptr + sizeof(short); break; default: rb_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[1]; pass[0] = 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); offset = 0; switch( data->ctype ){ case DLPTR_CTYPE_STRUCT: 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': case 'S': DLALIGN(data->ptr,offset,VOIDP_ALIGN); break; 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: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } return cary2ary((char *)data->ptr + offset, data->stype[i], data->ssize[i]); } switch( data->stype[i] ){ case 'I': offset += sizeof(int) * data->ssize[i]; break; case 'L': offset += sizeof(long) * data->ssize[i]; break; case 'P': case 'S': offset += sizeof(void*) * data->ssize[i]; break; case 'F': offset += sizeof(float) * data->ssize[i]; break; case 'D': offset += sizeof(double) * data->ssize[i]; break; case 'C': offset += sizeof(char) * data->ssize[i]; break; case 'H': offset += sizeof(short) * data->ssize[i]; break; default: rb_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((char *)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; long len; StringValue(val); Data_Get_Struct(self, struct ptr_data, data); dst = (void*)((long)(data->ptr) + DLNUM2LONG(key)); src = RSTRING(val)->ptr; len = RSTRING(val)->len; if( num == Qnil ){ memcpy(dst, src, len); } else{ long n = NUM2INT(num); memcpy(dst, src, n < len ? n : len); if( n > len ) MEMZERO((char*)dst + len, char, n - 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': case 'S': 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: rb_raise(rb_eDLTypeError, "unsupported type '%c'", data->stype[i]); } memimg = ary2cary(data->stype[i], val, &memsize); memcpy((char *)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': case 'S': case 's': 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: rb_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': case 'S': case 's': 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: rb_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; if( rb_scan_args(argc, argv, "01", &size) == 0){ return DLLONG2NUM(RDLPTR(self)->size); } else{ 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_cObject); rb_define_singleton_method(rb_cDLPtrData, "allocate", rb_dlptr_s_allocate, 0); rb_define_singleton_method(rb_cDLPtrData, "malloc", rb_dlptr_s_malloc, -1); rb_define_method(rb_cDLPtrData, "initialize", rb_dlptr_initialize, -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, "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); }