/* -*- mode: C; c-file-style: "gnu" -*- /* * $Id$ */ #include #include #include #include "dl.h" VALUE rb_mDL; VALUE rb_eDLError; VALUE rb_eDLTypeError; static VALUE DLFuncTable; static void *rb_dl_callback_table[CALLBACK_TYPES][MAX_CALLBACK]; static ID id_call; static int rb_dl_scan_callback_args(long stack[], const char *proto, int *argc, VALUE argv[]) { int i; long *sp; VALUE val; sp = stack; for (i=1; proto[i]; i++) { switch (proto[i]) { case 'C': { char v; v = (char)(*sp); sp++; val = INT2NUM(v); } break; case 'H': { short v; v = (short)(*sp); sp++; val = INT2NUM(v); } break; case 'I': { int v; v = (int)(*sp); sp++; val = INT2NUM(v); } break; case 'L': { long v; v = (long)(*sp); sp++; val = INT2NUM(v); } break; case 'F': { float v; memcpy(&v, sp, sizeof(float)); sp += sizeof(float)/sizeof(long); val = rb_float_new(v); } break; case 'D': { double v; memcpy(&v, sp, sizeof(double)); sp += sizeof(double)/sizeof(long); val = rb_float_new(v); } break; case 'P': { void *v; memcpy(&v, sp, sizeof(void*)); sp++; val = rb_dlptr_new(v, 0, 0); } break; case 'S': { char *v; memcpy(&v, sp, sizeof(void*)); sp++; val = rb_tainted_str_new2(v); } break; default: rb_raise(rb_eDLTypeError, "unsupported type `%c'", proto[i]); break; } argv[i-1] = val; } *argc = (i - 1); return (*argc); } #include "callback.func" static void init_dl_func_table(){ #include "cbtable.func" } void * dlmalloc(size_t size) { DEBUG_CODE2({ void *ptr; printf("dlmalloc(%d)",size); ptr = xmalloc(size); printf(":0x%x\n",ptr); return ptr; }, { return xmalloc(size); }); } void * dlrealloc(void *ptr, size_t size) { DEBUG_CODE({ printf("dlrealloc(0x%x,%d)\n",ptr,size); }); return xrealloc(ptr, size); } void dlfree(void *ptr) { DEBUG_CODE({ printf("dlfree(0x%x)\n",ptr); }); xfree(ptr); } char* dlstrdup(const char *str) { char *newstr; newstr = (char*)dlmalloc(strlen(str)); strcpy(newstr,str); return newstr; } size_t dlsizeof(const char *cstr) { size_t size; int i, len, n, dlen; char *d; len = strlen(cstr); size = 0; for (i=0; ilen; *size = sizeof(float) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FLOAT: ary[i] = (float)(RFLOAT(e)->value); break; case T_NIL: ary[i] = 0.0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static double * c_darray(VALUE v, long *size) { int i, len; double *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(double) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FLOAT: ary[i] = (double)(RFLOAT(e)->value); break; case T_NIL: ary[i] = 0.0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static long * c_larray(VALUE v, long *size) { int i, len; long *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(long) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (long)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static int * c_iarray(VALUE v, long *size) { int i, len; int *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(int) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (int)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static short * c_harray(VALUE v, long *size) { int i, len; short *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(short) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (short)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static char * c_carray(VALUE v, long *size) { int i, len; char *ary; VALUE e; len = RARRAY(v)->len; *size = sizeof(char) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { case T_FIXNUM: case T_BIGNUM: ary[i] = (char)(NUM2INT(e)); break; case T_NIL: ary[i] = 0; break; default: rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); break; } } return ary; } static void * c_parray(VALUE v, long *size) { int i, len; void **ary; VALUE e, tmp; len = RARRAY(v)->len; *size = sizeof(void*) * len; ary = dlmalloc(*size); for (i=0; i < len; i++) { e = rb_ary_entry(v, i); switch (TYPE(e)) { default: tmp = rb_check_string_type(e); if (NIL_P(tmp)) { rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); } e = tmp; /* fall through */ case T_STRING: rb_check_safe_str(e); { char *str, *src; src = RSTRING(e)->ptr; str = dlstrdup(src); ary[i] = (void*)str; } break; case T_NIL: ary[i] = NULL; break; case T_DATA: if (rb_obj_is_kind_of(e, rb_cDLPtrData)) { struct ptr_data *pdata; Data_Get_Struct(e, struct ptr_data, pdata); ary[i] = (void*)(pdata->ptr); } else{ rb_raise(rb_eDLTypeError, "unexpected type of the element #%d", i); } break; } } return ary; } void * rb_ary2cary(char t, VALUE v, long *size) { int len; VALUE val0; val0 = rb_check_array_type(v); if(NIL_P(TYPE(val0))) { rb_raise(rb_eDLTypeError, "an array is expected."); } v = val0; len = RARRAY(v)->len; if (len == 0) { return NULL; } if (!size) { size = ALLOCA_N(long,1); } val0 = rb_ary_entry(v,0); switch (TYPE(val0)) { case T_FIXNUM: case T_BIGNUM: switch (t) { case 'C': case 'c': return (void*)c_carray(v,size); case 'H': case 'h': return (void*)c_harray(v,size); case 'I': case 'i': return (void*)c_iarray(v,size); case 'L': case 'l': case 0: return (void*)c_larray(v,size); default: rb_raise(rb_eDLTypeError, "type mismatch"); } case T_STRING: return (void*)c_parray(v,size); case T_FLOAT: switch (t) { case 'F': case 'f': return (void*)c_farray(v,size); case 'D': case 'd': case 0: return (void*)c_darray(v,size); } rb_raise(rb_eDLTypeError, "type mismatch"); case T_DATA: if (rb_obj_is_kind_of(val0, rb_cDLPtrData)) { return (void*)c_parray(v,size); } rb_raise(rb_eDLTypeError, "type mismatch"); case T_NIL: return (void*)c_parray(v, size); default: rb_raise(rb_eDLTypeError, "unsupported type"); } } VALUE rb_str_to_ptr(VALUE self) { char *ptr; int len; len = RSTRING(self)->len; ptr = (char*)dlmalloc(len + 1); memcpy(ptr, RSTRING(self)->ptr, len); ptr[len] = '\0'; return rb_dlptr_new((void*)ptr,len,dlfree); } VALUE rb_ary_to_ptr(int argc, VALUE argv[], VALUE self) { void *ptr; VALUE t; long size; switch (rb_scan_args(argc, argv, "01", &t)) { case 1: ptr = rb_ary2cary(StringValuePtr(t)[0], self, &size); break; case 0: ptr = rb_ary2cary(0, self, &size); break; } return ptr ? rb_dlptr_new(ptr, size, dlfree) : Qnil; } VALUE rb_io_to_ptr(VALUE self) { OpenFile *fptr; FILE *fp; GetOpenFile(self, fptr); fp = fptr->f; return fp ? rb_dlptr_new(fp, sizeof(FILE), 0) : Qnil; } VALUE rb_dl_dlopen(int argc, VALUE argv[], VALUE self) { rb_secure(4); return rb_class_new_instance(argc, argv, rb_cDLHandle); } VALUE rb_dl_malloc(VALUE self, VALUE size) { rb_secure(4); return rb_dlptr_malloc(DLNUM2LONG(size), dlfree); } VALUE rb_dl_strdup(VALUE self, VALUE str) { void *ptr; long len; SafeStringValue(str); len = RSTRING(str)->len; ptr = memcpy(dlmalloc(len + 1), RSTRING(str)->ptr, len + 1); ((char *)ptr)[len] = '\0'; return rb_dlptr_new(ptr, len, dlfree); } static VALUE rb_dl_sizeof(VALUE self, VALUE str) { return INT2NUM(dlsizeof(StringValuePtr(str))); } static VALUE rb_dl_callback(int argc, VALUE argv[], VALUE self) { VALUE type, proc; int rettype, entry, i; char fname[127]; rb_secure(4); proc = Qnil; switch (rb_scan_args(argc, argv, "11", &type, &proc)) { case 1: if (rb_block_given_p()) { proc = rb_block_proc(); } else{ proc = Qnil; } default: break; } StringValue(type); switch (RSTRING(type)->ptr[0]) { case '0': rettype = 0x00; break; case 'C': rettype = 0x01; break; case 'H': rettype = 0x02; break; case 'I': rettype = 0x03; break; case 'L': rettype = 0x04; break; case 'F': rettype = 0x05; break; case 'D': rettype = 0x06; break; case 'P': rettype = 0x07; break; default: rb_raise(rb_eDLTypeError, "unsupported type `%c'", RSTRING(type)->ptr[0]); } entry = -1; for (i=0; i < MAX_CALLBACK; i++) { if (rb_hash_aref(DLFuncTable, rb_assoc_new(INT2NUM(rettype), INT2NUM(i))) == Qnil) { entry = i; break; } } if (entry < 0) { rb_raise(rb_eDLError, "too many callbacks are defined."); } rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(rettype),INT2NUM(entry)), rb_assoc_new(type,proc)); sprintf(fname, "rb_dl_callback_func_%d_%d", rettype, entry); return rb_dlsym_new((void (*)())rb_dl_callback_table[rettype][entry], fname, RSTRING(type)->ptr); } static VALUE rb_dl_remove_callback(VALUE mod, VALUE sym) { freefunc_t f; int i, j; rb_secure(4); f = rb_dlsym2csym(sym); for (i=0; i < CALLBACK_TYPES; i++) { for (j=0; j < MAX_CALLBACK; j++) { if (rb_dl_callback_table[i][j] == f) { rb_hash_aset(DLFuncTable, rb_assoc_new(INT2NUM(i),INT2NUM(j)),Qnil); break; } } } return Qnil; } void Init_dl() { void Init_dlptr(); void Init_dlsym(); void Init_dlhandle(); id_call = rb_intern("call"); rb_mDL = rb_define_module("DL"); rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError); rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError); DLFuncTable = rb_hash_new(); init_dl_func_table(); rb_define_const(rb_mDL, "FuncTable", DLFuncTable); rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL)); rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY)); rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW)); rb_define_const(rb_mDL, "ALIGN_INT", INT2NUM(ALIGN_INT)); rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); rb_define_const(rb_mDL, "MAX_ARG", INT2NUM(MAX_ARG)); rb_define_const(rb_mDL, "DLSTACK", rb_tainted_str_new2(DLSTACK_METHOD)); rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1); rb_define_module_function(rb_mDL, "callback", rb_dl_callback, -1); rb_define_module_function(rb_mDL, "define_callback", rb_dl_callback, -1); rb_define_module_function(rb_mDL, "remove_callback", rb_dl_remove_callback, 1); rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1); rb_define_module_function(rb_mDL, "strdup", rb_dl_strdup, 1); rb_define_module_function(rb_mDL, "sizeof", rb_dl_sizeof, 1); Init_dlptr(); Init_dlsym(); Init_dlhandle(); rb_define_const(rb_mDL, "FREE", rb_dlsym_new(dlfree, "free", "0P")); rb_define_method(rb_cString, "to_ptr", rb_str_to_ptr, 0); rb_define_method(rb_cArray, "to_ptr", rb_ary_to_ptr, -1); rb_define_method(rb_cIO, "to_ptr", rb_io_to_ptr, 0); }