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; }
static VALUE rb_dlptr_initialize(int argc, VALUE argv[], VALUE self) { VALUE ptr, sym, 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; }
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_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_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_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_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_eql(VALUE self, VALUE other) { void *ptr1, *ptr2; ptr1 = rb_dlptr2cptr(self); ptr2 = rb_dlptr2cptr(other); return ptr1 == ptr2 ? Qtrue : Qfalse; }
VALUE rb_dlptr_aref(int argc, VALUE argv[], VALUE self) { VALUE key = Qnil, num = Qnil; ID id; 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)); } rb_to_id(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++) { 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]); } if (data->ids[i] == id) { 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; }
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; rb_secure(4); 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; } 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++) { 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]); } if (data->ids[i] == id) { memimg = ary2cary(data->stype[i], val, &memsize); memcpy((char *)data->ptr + offset, memimg, memsize); dlfree(memimg); 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); dlfree(memimg); } } 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_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); }
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, num; char *ctype; 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; i<num; i++) { rb_to_id(rb_ary_entry(rest,i)); } 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 = StringValuePtr(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(RSTRING(type)->ptr); return Qnil; }
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_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_free_set(VALUE self, VALUE val) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); data->free = DLFREEFUNC(rb_dlsym2csym(val)); return Qnil; }
VALUE rb_dlptr_inspect(VALUE self) { struct ptr_data *data; char str[1024]; Data_Get_Struct(self, struct ptr_data, data); snprintf(str, 1023, "#<%s:0x%lx ptr=0x%lx size=%ld free=0x%lx>", rb_class2name(CLASS_OF(self)), data, data->ptr, data->size, (long)data->free); return rb_str_new2(str); }
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_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_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; } }
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; } }
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_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 'P': case 'p': n = data->size / sizeof(void*); break; case 'S': case 's': for (n=0; ((void**)(data->ptr))[n]; n++) {}; break; default: 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])); break; 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_i(VALUE self) { struct ptr_data *data; Data_Get_Struct(self, struct ptr_data, data); return DLLONG2NUM(data->ptr); }
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_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); }