static VALUE dlhandle_sym(void *handle, const char *name) { #if defined(HAVE_DLERROR) const char *err; # define CHECK_DLERROR if( err = dlerror() ){ func = 0; } #else # define CHECK_DLERROR #endif void (*func)() = dlsym(handle, name); CHECK_DLERROR; #if defined(FUNC_STDCALL) if( !func ){ int i; int len = strlen(name); char *name_n; #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__) { char *name_a = (char*)xmalloc(len+2); strcpy(name_a, name); name_n = name_a; name_a[len] = 'A'; name_a[len+1] = '\0'; func = dlsym(handle, name_a); CHECK_DLERROR; if( func ) goto found; name_n = xrealloc(name_a, len+6); } #else name_n = (char*)xmalloc(len+6); #endif memcpy(name_n, name, len); name_n[len++] = '@'; for( i = 0; i < 256; i += 4 ){ sprintf(name_n + len, "%d", i); func = dlsym(handle, name_n); CHECK_DLERROR; if( func ) break; } if( func ) goto found; name_n[len-1] = 'A'; name_n[len++] = '@'; for( i = 0; i < 256; i += 4 ){ sprintf(name_n + len, "%d", i); func = dlsym(handle, name_n); CHECK_DLERROR; if( func ) break; } found: xfree(name_n); } #endif if( !func ){ rb_raise(rb_eDLError, "unknown symbol \"%s\"", name); } return PTR2NUM(func); }
/* * call-seq: Fiddle.realloc(addr, size) * * Change the size of the memory allocated at the memory location +addr+ to * +size+ bytes. Returns the memory address of the reallocated memory, which * may be different than the address passed in. */ static VALUE rb_fiddle_realloc(VALUE self, VALUE addr, VALUE size) { void *ptr = NUM2PTR(addr); ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size)); return PTR2NUM(ptr); }
/* * call-seq: Fiddle.malloc(size) * * Allocate +size+ bytes of memory and return the integer memory address * for the allocated memory. */ static VALUE rb_fiddle_malloc(VALUE self, VALUE size) { void *ptr; ptr = (void*)ruby_xmalloc(NUM2INT(size)); return PTR2NUM(ptr); }
/* * call-seq: to_i * * Returns the memory address for this handle. */ static VALUE rb_fiddle_handle_to_i(VALUE self) { struct dl_handle *fiddle_handle; TypedData_Get_Struct(self, struct dl_handle, &fiddle_handle_data_type, fiddle_handle); return PTR2NUM(fiddle_handle); }
/* * call-seq: to_i * * Returns the memory address for this handle. */ VALUE rb_dlhandle_to_i(VALUE self) { struct dl_handle *dlhandle; TypedData_Get_Struct(self, struct dl_handle, &dlhandle_data_type, dlhandle); return PTR2NUM(dlhandle); }
static VALUE initialize(int argc, VALUE argv[], VALUE self) { ffi_cif * cif; ffi_type **arg_types, *rtype; ffi_status result; VALUE ptr, args, ret_type, abi, kwds, ary; int i, len; int nabi; void *cfunc; rb_scan_args(argc, argv, "31:", &ptr, &args, &ret_type, &abi, &kwds); ptr = rb_Integer(ptr); cfunc = NUM2PTR(ptr); PTR2NUM(cfunc); nabi = NIL_P(abi) ? FFI_DEFAULT_ABI : NUM2INT(abi); abi = INT2FIX(nabi); i = NUM2INT(ret_type); rtype = INT2FFI_TYPE(i); ret_type = INT2FIX(i); Check_Type(args, T_ARRAY); len = RARRAY_LENINT(args); Check_Max_Args("args", len); ary = rb_ary_subseq(args, 0, len); for (i = 0; i < RARRAY_LEN(args); i++) { VALUE a = RARRAY_PTR(args)[i]; int type = NUM2INT(a); (void)INT2FFI_TYPE(type); /* raise */ if (INT2FIX(type) != a) rb_ary_store(ary, i, INT2FIX(type)); } OBJ_FREEZE(ary); rb_iv_set(self, "@ptr", ptr); rb_iv_set(self, "@args", args); rb_iv_set(self, "@return_type", ret_type); rb_iv_set(self, "@abi", abi); if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self); TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif); arg_types = xcalloc(len + 1, sizeof(ffi_type *)); for (i = 0; i < RARRAY_LEN(args); i++) { int type = NUM2INT(RARRAY_AREF(args, i)); arg_types[i] = INT2FFI_TYPE(type); } arg_types[len] = NULL; result = ffi_prep_cif(cif, nabi, len, rtype, arg_types); if (result) rb_raise(rb_eRuntimeError, "error creating CIF %d", result); return self; }
static VALUE cr_to_ptr (VALUE self) { if (NIL_P (rb_cairo__cFFIPointer)) return Qnil; return rb_funcall (rb_cairo__cFFIPointer, rb_intern ("new"), 1, PTR2NUM (_SELF)); }
/* * call-seq: DL.realloc(addr, size) * * Change the size of the memory allocated at the memory location +addr+ to * +size+ bytes. Returns the memory address of the reallocated memory, which * may be different than the address passed in. */ VALUE rb_dl_realloc(VALUE self, VALUE addr, VALUE size) { void *ptr = NUM2PTR(addr); rb_secure(4); ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size)); return PTR2NUM(ptr); }
/* * call-seq: DL.malloc * * Allocate +size+ bytes of memory and return the integer memory address * for the allocated memory. */ VALUE rb_dl_malloc(VALUE self, VALUE size) { void *ptr; rb_secure(4); ptr = (void*)ruby_xmalloc(NUM2INT(size)); return PTR2NUM(ptr); }
static VALUE cr_win32_surface_get_hdc (VALUE self) { HDC hdc; hdc = cairo_win32_surface_get_dc (_SELF); if (!hdc) return Qnil; else return PTR2NUM (hdc); }
static VALUE to_i(VALUE self) { fiddle_closure * cl; void *code; TypedData_Get_Struct(self, fiddle_closure, &closure_data_type, cl); code = cl->code; return PTR2NUM(code); }
VALUE generic_to_value(VALUE rettype, fiddle_generic retval) { int type = NUM2INT(rettype); VALUE cPointer; cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); switch (type) { case TYPE_VOID: return Qnil; case TYPE_VOIDP: return rb_funcall(cPointer, rb_intern("[]"), 1, PTR2NUM((void *)retval.pointer)); case TYPE_CHAR: return INT2NUM((signed char)retval.fffi_sarg); case -TYPE_CHAR: return INT2NUM((unsigned char)retval.fffi_arg); case TYPE_SHORT: return INT2NUM((signed short)retval.fffi_sarg); case -TYPE_SHORT: return INT2NUM((unsigned short)retval.fffi_arg); case TYPE_INT: return INT2NUM((signed int)retval.fffi_sarg); case -TYPE_INT: return UINT2NUM((unsigned int)retval.fffi_arg); case TYPE_LONG: return LONG2NUM(retval.slong); case -TYPE_LONG: return ULONG2NUM(retval.ulong); #if HAVE_LONG_LONG case TYPE_LONG_LONG: return LL2NUM(retval.slong_long); case -TYPE_LONG_LONG: return ULL2NUM(retval.ulong_long); #endif case TYPE_FLOAT: return rb_float_new(retval.ffloat); case TYPE_DOUBLE: return rb_float_new(retval.ddouble); default: rb_raise(rb_eRuntimeError, "unknown type %d", type); } UNREACHABLE; }
VALUE generic_to_value(VALUE rettype, fiddle_generic retval) { int signed_p = 1; int type = NUM2INT(rettype); VALUE cPointer; cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); if (type < 0) { type = -1 * type; signed_p = 0; } switch (type) { case TYPE_VOID: return Qnil; case TYPE_VOIDP: return rb_funcall(cPointer, rb_intern("[]"), 1, PTR2NUM((void *)retval.pointer)); case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: return INT2NUM(retval.sint); case TYPE_LONG: if (signed_p) return LONG2NUM(retval.slong); return ULONG2NUM(retval.ulong); #if HAVE_LONG_LONG case TYPE_LONG_LONG: return rb_ll2inum(retval.long_long); break; #endif case TYPE_FLOAT: return rb_float_new(retval.ffloat); case TYPE_DOUBLE: return rb_float_new(retval.ddouble); default: rb_raise(rb_eRuntimeError, "unknown type %d", type); } }
VALUE rb_dl_value2ptr(VALUE self, VALUE val) { return PTR2NUM((void*)val); }
static VALUE fiddle_handle_sym(void *handle, VALUE symbol) { #if defined(HAVE_DLERROR) const char *err; # define CHECK_DLERROR if ((err = dlerror()) != 0) { func = 0; } #else # define CHECK_DLERROR #endif void (*func)(); const char *name = SafeStringValueCStr(symbol); rb_secure(2); #ifdef HAVE_DLERROR dlerror(); #endif func = (void (*)())(VALUE)dlsym(handle, name); CHECK_DLERROR; #if defined(FUNC_STDCALL) if( !func ){ int i; int len = (int)strlen(name); char *name_n; #if defined(__CYGWIN__) || defined(_WIN32) || defined(__MINGW32__) { char *name_a = (char*)xmalloc(len+2); strcpy(name_a, name); name_n = name_a; name_a[len] = 'A'; name_a[len+1] = '\0'; func = dlsym(handle, name_a); CHECK_DLERROR; if( func ) goto found; name_n = xrealloc(name_a, len+6); } #else name_n = (char*)xmalloc(len+6); #endif memcpy(name_n, name, len); name_n[len++] = '@'; for( i = 0; i < 256; i += 4 ){ sprintf(name_n + len, "%d", i); func = dlsym(handle, name_n); CHECK_DLERROR; if( func ) break; } if( func ) goto found; name_n[len-1] = 'A'; name_n[len++] = '@'; for( i = 0; i < 256; i += 4 ){ sprintf(name_n + len, "%d", i); func = dlsym(handle, name_n); CHECK_DLERROR; if( func ) break; } found: xfree(name_n); } #endif if( !func ){ rb_raise(rb_eFiddleError, "unknown symbol \"%"PRIsVALUE"\"", symbol); } return PTR2NUM(func); }
void Init_fiddle(void) { /* * Document-module: Fiddle * * A libffi wrapper for Ruby. * * == Description * * Fiddle is an extension to translate a foreign function interface (FFI) * with ruby. * * It wraps {libffi}[http://sourceware.org/libffi/], a popular C library * which provides a portable interface that allows code written in one * language to call code written in another language. * * == Example * * Here we will use Fiddle::Function to wrap {floor(3) from * libm}[http://linux.die.net/man/3/floor] * * require 'fiddle' * * libm = Fiddle.dlopen('/lib/libm.so.6') * * floor = Fiddle::Function.new( * libm['floor'], * [Fiddle::TYPE_DOUBLE], * Fiddle::TYPE_DOUBLE * ) * * puts floor.call(3.14159) #=> 3.0 * * */ mFiddle = rb_define_module("Fiddle"); /* * Document-class: Fiddle::DLError * * standard dynamic load exception */ rb_eFiddleError = rb_define_class_under(mFiddle, "DLError", rb_eStandardError); /* Document-const: TYPE_VOID * * C type - void */ rb_define_const(mFiddle, "TYPE_VOID", INT2NUM(TYPE_VOID)); /* Document-const: TYPE_VOIDP * * C type - void* */ rb_define_const(mFiddle, "TYPE_VOIDP", INT2NUM(TYPE_VOIDP)); /* Document-const: TYPE_CHAR * * C type - char */ rb_define_const(mFiddle, "TYPE_CHAR", INT2NUM(TYPE_CHAR)); /* Document-const: TYPE_SHORT * * C type - short */ rb_define_const(mFiddle, "TYPE_SHORT", INT2NUM(TYPE_SHORT)); /* Document-const: TYPE_INT * * C type - int */ rb_define_const(mFiddle, "TYPE_INT", INT2NUM(TYPE_INT)); /* Document-const: TYPE_LONG * * C type - long */ rb_define_const(mFiddle, "TYPE_LONG", INT2NUM(TYPE_LONG)); #if HAVE_LONG_LONG /* Document-const: TYPE_LONG_LONG * * C type - long long */ rb_define_const(mFiddle, "TYPE_LONG_LONG", INT2NUM(TYPE_LONG_LONG)); #endif /* Document-const: TYPE_FLOAT * * C type - float */ rb_define_const(mFiddle, "TYPE_FLOAT", INT2NUM(TYPE_FLOAT)); /* Document-const: TYPE_DOUBLE * * C type - double */ rb_define_const(mFiddle, "TYPE_DOUBLE", INT2NUM(TYPE_DOUBLE)); /* Document-const: TYPE_SIZE_T * * C type - size_t */ rb_define_const(mFiddle, "TYPE_SIZE_T", INT2NUM(TYPE_SIZE_T)); /* Document-const: TYPE_SSIZE_T * * C type - ssize_t */ rb_define_const(mFiddle, "TYPE_SSIZE_T", INT2NUM(TYPE_SSIZE_T)); /* Document-const: TYPE_PTRDIFF_T * * C type - ptrdiff_t */ rb_define_const(mFiddle, "TYPE_PTRDIFF_T", INT2NUM(TYPE_PTRDIFF_T)); /* Document-const: TYPE_INTPTR_T * * C type - intptr_t */ rb_define_const(mFiddle, "TYPE_INTPTR_T", INT2NUM(TYPE_INTPTR_T)); /* Document-const: TYPE_UINTPTR_T * * C type - uintptr_t */ rb_define_const(mFiddle, "TYPE_UINTPTR_T", INT2NUM(TYPE_UINTPTR_T)); /* Document-const: ALIGN_VOIDP * * The alignment size of a void* */ rb_define_const(mFiddle, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); /* Document-const: ALIGN_CHAR * * The alignment size of a char */ rb_define_const(mFiddle, "ALIGN_CHAR", INT2NUM(ALIGN_CHAR)); /* Document-const: ALIGN_SHORT * * The alignment size of a short */ rb_define_const(mFiddle, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); /* Document-const: ALIGN_INT * * The alignment size of an int */ rb_define_const(mFiddle, "ALIGN_INT", INT2NUM(ALIGN_INT)); /* Document-const: ALIGN_LONG * * The alignment size of a long */ rb_define_const(mFiddle, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); #if HAVE_LONG_LONG /* Document-const: ALIGN_LONG_LONG * * The alignment size of a long long */ rb_define_const(mFiddle, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG)); #endif /* Document-const: ALIGN_FLOAT * * The alignment size of a float */ rb_define_const(mFiddle, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); /* Document-const: ALIGN_DOUBLE * * The alignment size of a double */ rb_define_const(mFiddle, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); /* Document-const: ALIGN_SIZE_T * * The alignment size of a size_t */ rb_define_const(mFiddle, "ALIGN_SIZE_T", INT2NUM(ALIGN_OF(size_t))); /* Document-const: ALIGN_SSIZE_T * * The alignment size of a ssize_t */ rb_define_const(mFiddle, "ALIGN_SSIZE_T", INT2NUM(ALIGN_OF(size_t))); /* same as size_t */ /* Document-const: ALIGN_PTRDIFF_T * * The alignment size of a ptrdiff_t */ rb_define_const(mFiddle, "ALIGN_PTRDIFF_T", INT2NUM(ALIGN_OF(ptrdiff_t))); /* Document-const: ALIGN_INTPTR_T * * The alignment size of a intptr_t */ rb_define_const(mFiddle, "ALIGN_INTPTR_T", INT2NUM(ALIGN_OF(intptr_t))); /* Document-const: ALIGN_UINTPTR_T * * The alignment size of a uintptr_t */ rb_define_const(mFiddle, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t))); /* Document-const: WINDOWS * * Returns a boolean regarding whether the host is WIN32 */ #if defined(_WIN32) rb_define_const(mFiddle, "WINDOWS", Qtrue); #else rb_define_const(mFiddle, "WINDOWS", Qfalse); #endif /* Document-const: SIZEOF_VOIDP * * size of a void* */ rb_define_const(mFiddle, "SIZEOF_VOIDP", INT2NUM(sizeof(void*))); /* Document-const: SIZEOF_CHAR * * size of a char */ rb_define_const(mFiddle, "SIZEOF_CHAR", INT2NUM(sizeof(char))); /* Document-const: SIZEOF_SHORT * * size of a short */ rb_define_const(mFiddle, "SIZEOF_SHORT", INT2NUM(sizeof(short))); /* Document-const: SIZEOF_INT * * size of an int */ rb_define_const(mFiddle, "SIZEOF_INT", INT2NUM(sizeof(int))); /* Document-const: SIZEOF_LONG * * size of a long */ rb_define_const(mFiddle, "SIZEOF_LONG", INT2NUM(sizeof(long))); #if HAVE_LONG_LONG /* Document-const: SIZEOF_LONG_LONG * * size of a long long */ rb_define_const(mFiddle, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG))); #endif /* Document-const: SIZEOF_FLOAT * * size of a float */ rb_define_const(mFiddle, "SIZEOF_FLOAT", INT2NUM(sizeof(float))); /* Document-const: SIZEOF_DOUBLE * * size of a double */ rb_define_const(mFiddle, "SIZEOF_DOUBLE",INT2NUM(sizeof(double))); /* Document-const: SIZEOF_SIZE_T * * size of a size_t */ rb_define_const(mFiddle, "SIZEOF_SIZE_T", INT2NUM(sizeof(size_t))); /* Document-const: SIZEOF_SSIZE_T * * size of a ssize_t */ rb_define_const(mFiddle, "SIZEOF_SSIZE_T", INT2NUM(sizeof(size_t))); /* same as size_t */ /* Document-const: SIZEOF_PTRDIFF_T * * size of a ptrdiff_t */ rb_define_const(mFiddle, "SIZEOF_PTRDIFF_T", INT2NUM(sizeof(ptrdiff_t))); /* Document-const: SIZEOF_INTPTR_T * * size of a intptr_t */ rb_define_const(mFiddle, "SIZEOF_INTPTR_T", INT2NUM(sizeof(intptr_t))); /* Document-const: SIZEOF_UINTPTR_T * * size of a uintptr_t */ rb_define_const(mFiddle, "SIZEOF_UINTPTR_T", INT2NUM(sizeof(uintptr_t))); /* Document-const: RUBY_FREE * * Address of the ruby_xfree() function */ rb_define_const(mFiddle, "RUBY_FREE", PTR2NUM(ruby_xfree)); /* Document-const: BUILD_RUBY_PLATFORM * * Platform built against (i.e. "x86_64-linux", etc.) * * See also RUBY_PLATFORM */ rb_define_const(mFiddle, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM)); rb_define_module_function(mFiddle, "dlwrap", rb_fiddle_value2ptr, 1); rb_define_module_function(mFiddle, "dlunwrap", rb_fiddle_ptr2value, 1); rb_define_module_function(mFiddle, "malloc", rb_fiddle_malloc, 1); rb_define_module_function(mFiddle, "realloc", rb_fiddle_realloc, 2); rb_define_module_function(mFiddle, "free", rb_fiddle_free, 1); Init_fiddle_function(); Init_fiddle_closure(); Init_fiddle_handle(); Init_fiddle_pointer(); }
void callback(ffi_cif *cif, void *resp, void **args, void *ctx) { VALUE self = (VALUE)ctx; VALUE rbargs = rb_iv_get(self, "@args"); VALUE ctype = rb_iv_get(self, "@ctype"); int argc = RARRAY_LENINT(rbargs); VALUE params = rb_ary_tmp_new(argc); VALUE ret; VALUE cPointer; int i, type; cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); for (i = 0; i < argc; i++) { type = NUM2INT(RARRAY_PTR(rbargs)[i]); switch (type) { case TYPE_VOID: argc = 0; break; case TYPE_INT: rb_ary_push(params, INT2NUM(*(int *)args[i])); break; case -TYPE_INT: rb_ary_push(params, UINT2NUM(*(unsigned int *)args[i])); break; case TYPE_VOIDP: rb_ary_push(params, rb_funcall(cPointer, rb_intern("[]"), 1, PTR2NUM(*(void **)args[i]))); break; case TYPE_LONG: rb_ary_push(params, LONG2NUM(*(long *)args[i])); break; case -TYPE_LONG: rb_ary_push(params, ULONG2NUM(*(unsigned long *)args[i])); break; case TYPE_CHAR: rb_ary_push(params, INT2NUM(*(signed char *)args[i])); break; case -TYPE_CHAR: rb_ary_push(params, UINT2NUM(*(unsigned char *)args[i])); break; case TYPE_SHORT: rb_ary_push(params, INT2NUM(*(signed short *)args[i])); break; case -TYPE_SHORT: rb_ary_push(params, UINT2NUM(*(unsigned short *)args[i])); break; case TYPE_DOUBLE: rb_ary_push(params, rb_float_new(*(double *)args[i])); break; case TYPE_FLOAT: rb_ary_push(params, rb_float_new(*(float *)args[i])); break; #if HAVE_LONG_LONG case TYPE_LONG_LONG: rb_ary_push(params, LL2NUM(*(LONG_LONG *)args[i])); break; case -TYPE_LONG_LONG: rb_ary_push(params, ULL2NUM(*(unsigned LONG_LONG *)args[i])); break; #endif default: rb_raise(rb_eRuntimeError, "closure args: %d", type); } } ret = rb_funcall2(self, rb_intern("call"), argc, RARRAY_PTR(params)); RB_GC_GUARD(params); type = NUM2INT(ctype); switch (type) { case TYPE_VOID: break; case TYPE_LONG: *(long *)resp = NUM2LONG(ret); break; case -TYPE_LONG: *(unsigned long *)resp = NUM2ULONG(ret); break; case TYPE_CHAR: case TYPE_SHORT: case TYPE_INT: *(ffi_sarg *)resp = NUM2INT(ret); break; case -TYPE_CHAR: case -TYPE_SHORT: case -TYPE_INT: *(ffi_arg *)resp = NUM2UINT(ret); break; case TYPE_VOIDP: *(void **)resp = NUM2PTR(ret); break; case TYPE_DOUBLE: *(double *)resp = NUM2DBL(ret); break; case TYPE_FLOAT: *(float *)resp = (float)NUM2DBL(ret); break; #if HAVE_LONG_LONG case TYPE_LONG_LONG: *(LONG_LONG *)resp = NUM2LL(ret); break; case -TYPE_LONG_LONG: *(unsigned LONG_LONG *)resp = NUM2ULL(ret); break; #endif default: rb_raise(rb_eRuntimeError, "closure retval: %d", type); } }
VALUE rb_dlhandle_sym(VALUE self, VALUE sym) { void (*func)(); struct dl_handle *dlhandle; void *handle; const char *name; const char *err; int i; #if defined(HAVE_DLERROR) # define CHECK_DLERROR if( err = dlerror() ){ func = 0; } #else # define CHECK_DLERROR #endif rb_secure(2); if( sym == Qnil ){ #if defined(RTLD_NEXT) name = RTLD_NEXT; #else name = NULL; #endif } else{ name = StringValuePtr(sym); } Data_Get_Struct(self, struct dl_handle, dlhandle); if( ! dlhandle->open ){ rb_raise(rb_eDLError, "closed handle"); } handle = dlhandle->ptr; func = dlsym(handle, name); CHECK_DLERROR; if( !func ){ #if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__) { int len = strlen(name); char *name_a = (char*)xmalloc(len+2); strcpy(name_a, name); name_a[len] = 'A'; name_a[len+1] = '\0'; func = dlsym(handle, name_a); xfree(name_a); CHECK_DLERROR; if( !func ){ for( i = 0; i < 256; i += 4 ){ int len = strlen(name); char *name_n = (char*)xmalloc(len+5); sprintf(name_n, "%s@%d%c", name, i, 0); func = dlsym(handle, name_n); xfree(name_n); CHECK_DLERROR; if( func ) { break; } } CHECK_DLERROR; if( !func ){ rb_raise(rb_eDLError, "unknown symbol \"%s\"", name); } } } #else for( i = 0; i < 256; i += 4 ){ int len = strlen(name); char *name_n = (char*)xmalloc(len+4); sprintf(name_n, "%s@%d", name, i); func = dlsym(handle, name_n); xfree(name_n); CHECK_DLERROR; if( func ){ break; } } CHECK_DLERROR; if( !func ){ rb_raise(rb_eDLError, "unknown symbol \"%s\"", name); } #endif } return PTR2NUM(func); }
void callback(ffi_cif *cif, void *resp, void **args, void *ctx) { VALUE self = (VALUE)ctx; VALUE rbargs = rb_iv_get(self, "@args"); VALUE ctype = rb_iv_get(self, "@ctype"); int argc = RARRAY_LENINT(rbargs); VALUE *params = xcalloc(argc, sizeof(VALUE *)); VALUE ret; VALUE cPointer; int i, type; cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); for (i = 0; i < argc; i++) { type = NUM2INT(RARRAY_PTR(rbargs)[i]); switch (type) { case TYPE_VOID: argc = 0; break; case TYPE_INT: params[i] = INT2NUM(*(int *)args[i]); break; case TYPE_VOIDP: params[i] = rb_funcall(cPointer, rb_intern("[]"), 1, PTR2NUM(*(void **)args[i])); break; case TYPE_LONG: params[i] = LONG2NUM(*(long *)args[i]); break; case TYPE_CHAR: params[i] = INT2NUM(*(char *)args[i]); break; case TYPE_DOUBLE: params[i] = rb_float_new(*(double *)args[i]); break; case TYPE_FLOAT: params[i] = rb_float_new(*(float *)args[i]); break; #if HAVE_LONG_LONG case TYPE_LONG_LONG: params[i] = rb_ull2inum(*(unsigned LONG_LONG *)args[i]); break; #endif default: rb_raise(rb_eRuntimeError, "closure args: %d", type); } } ret = rb_funcall2(self, rb_intern("call"), argc, params); type = NUM2INT(ctype); switch (type) { case TYPE_VOID: break; case TYPE_LONG: *(long *)resp = NUM2LONG(ret); break; case TYPE_CHAR: *(char *)resp = NUM2INT(ret); break; case TYPE_VOIDP: *(void **)resp = NUM2PTR(ret); break; case TYPE_INT: *(int *)resp = NUM2INT(ret); break; case TYPE_DOUBLE: *(double *)resp = NUM2DBL(ret); break; case TYPE_FLOAT: *(float *)resp = (float)NUM2DBL(ret); break; #if HAVE_LONG_LONG case TYPE_LONG_LONG: *(unsigned LONG_LONG *)resp = rb_big2ull(ret); break; #endif default: rb_raise(rb_eRuntimeError, "closure retval: %d", type); } xfree(params); }
void Init_dl(void) { void Init_dlhandle(void); void Init_dlcfunc(void); void Init_dlptr(void); rbdl_id_cdecl = rb_intern_const("cdecl"); rbdl_id_stdcall = rb_intern_const("stdcall"); /* Document-module: DL * * A bridge to the dlopen() or dynamic library linker function. * * == Example * * bash $> cat > sum.c <<EOF * double sum(double *arry, int len) * { * double ret = 0; * int i; * for(i = 0; i < len; i++){ * ret = ret + arry[i]; * } * return ret; * } * * double split(double num) * { * double ret = 0; * ret = num / 2; * return ret; * } * EOF * bash $> gcc -o libsum.so -shared sum.c * bash $> cat > sum.rb <<EOF * require 'dl' * require 'dl/import' * * module LibSum * extend DL::Importer * dlload './libsum.so' * extern 'double sum(double*, int)' * extern 'double split(double)' * end * * a = [2.0, 3.0, 4.0] * * sum = LibSum.sum(a.pack("d*"), a.count) * p LibSum.split(sum) * EOF * bash $> ruby sum.rb * 4.5 * * WIN! :-) */ rb_mDL = rb_define_module("DL"); /* * Document-class: DL::DLError * * standard dynamic load exception */ rb_eDLError = rb_define_class_under(rb_mDL, "DLError", rb_eStandardError); /* * Document-class: DL::DLTypeError * * dynamic load incorrect type exception */ rb_eDLTypeError = rb_define_class_under(rb_mDL, "DLTypeError", rb_eDLError); /* Document-const: MAX_CALLBACK * * Maximum number of callbacks */ rb_define_const(rb_mDL, "MAX_CALLBACK", INT2NUM(MAX_CALLBACK)); /* Document-const: DLSTACK_SIZE * * Dynamic linker stack size */ rb_define_const(rb_mDL, "DLSTACK_SIZE", INT2NUM(DLSTACK_SIZE)); rb_dl_init_callbacks(rb_mDL); /* Document-const: RTLD_GLOBAL * * rtld DL::Handle flag. * * The symbols defined by this library will be made available for symbol * resolution of subsequently loaded libraries. */ rb_define_const(rb_mDL, "RTLD_GLOBAL", INT2NUM(RTLD_GLOBAL)); /* Document-const: RTLD_LAZY * * rtld DL::Handle flag. * * Perform lazy binding. Only resolve symbols as the code that references * them is executed. If the symbol is never referenced, then it is never * resolved. (Lazy binding is only performed for function references; * references to variables are always immediately bound when the library * is loaded.) */ rb_define_const(rb_mDL, "RTLD_LAZY", INT2NUM(RTLD_LAZY)); /* Document-const: RTLD_NOW * * rtld DL::Handle flag. * * If this value is specified or the environment variable LD_BIND_NOW is * set to a nonempty string, all undefined symbols in the library are * resolved before dlopen() returns. If this cannot be done an error is * returned. */ rb_define_const(rb_mDL, "RTLD_NOW", INT2NUM(RTLD_NOW)); /* Document-const: TYPE_VOID * * DL::CFunc type - void */ rb_define_const(rb_mDL, "TYPE_VOID", INT2NUM(DLTYPE_VOID)); /* Document-const: TYPE_VOIDP * * DL::CFunc type - void* */ rb_define_const(rb_mDL, "TYPE_VOIDP", INT2NUM(DLTYPE_VOIDP)); /* Document-const: TYPE_CHAR * * DL::CFunc type - char */ rb_define_const(rb_mDL, "TYPE_CHAR", INT2NUM(DLTYPE_CHAR)); /* Document-const: TYPE_SHORT * * DL::CFunc type - short */ rb_define_const(rb_mDL, "TYPE_SHORT", INT2NUM(DLTYPE_SHORT)); /* Document-const: TYPE_INT * * DL::CFunc type - int */ rb_define_const(rb_mDL, "TYPE_INT", INT2NUM(DLTYPE_INT)); /* Document-const: TYPE_LONG * * DL::CFunc type - long */ rb_define_const(rb_mDL, "TYPE_LONG", INT2NUM(DLTYPE_LONG)); #if HAVE_LONG_LONG /* Document-const: TYPE_LONG_LONG * * DL::CFunc type - long long */ rb_define_const(rb_mDL, "TYPE_LONG_LONG", INT2NUM(DLTYPE_LONG_LONG)); #endif /* Document-const: TYPE_FLOAT * * DL::CFunc type - float */ rb_define_const(rb_mDL, "TYPE_FLOAT", INT2NUM(DLTYPE_FLOAT)); /* Document-const: TYPE_DOUBLE * * DL::CFunc type - double */ rb_define_const(rb_mDL, "TYPE_DOUBLE", INT2NUM(DLTYPE_DOUBLE)); /* Document-const: ALIGN_VOIDP * * The Offset of a struct void* and a void* */ rb_define_const(rb_mDL, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP)); /* Document-const: ALIGN_CHAR * * The Offset of a struct char and a char */ rb_define_const(rb_mDL, "ALIGN_CHAR", INT2NUM(ALIGN_CHAR)); /* Document-const: ALIGN_SHORT * * The Offset of a struct short and a short */ rb_define_const(rb_mDL, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT)); /* Document-const: ALIGN_INT * * The Offset of a struct int and a int */ rb_define_const(rb_mDL, "ALIGN_INT", INT2NUM(ALIGN_INT)); /* Document-const: ALIGN_LONG * * The Offset of a struct long and a long */ rb_define_const(rb_mDL, "ALIGN_LONG", INT2NUM(ALIGN_LONG)); #if HAVE_LONG_LONG /* Document-const: ALIGN_LONG_LONG * * The Offset of a struct long long and a long long */ rb_define_const(rb_mDL, "ALIGN_LONG_LONG", INT2NUM(ALIGN_LONG_LONG)); #endif /* Document-const: ALIGN_FLOAT * * The Offset of a struct float and a float */ rb_define_const(rb_mDL, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT)); /* Document-const: ALIGN_DOUBLE * * The Offset of a struct double and a double */ rb_define_const(rb_mDL, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE)); /* Document-const: SIZEOF_VOIDP * * OS Dependent - sizeof(void*) */ rb_define_const(rb_mDL, "SIZEOF_VOIDP", INT2NUM(sizeof(void*))); /* Document-const: SIZEOF_CHAR * * OS Dependent - sizeof(char) */ rb_define_const(rb_mDL, "SIZEOF_CHAR", INT2NUM(sizeof(char))); /* Document-const: SIZEOF_SHORT * * OS Dependent - sizeof(short) */ rb_define_const(rb_mDL, "SIZEOF_SHORT", INT2NUM(sizeof(short))); /* Document-const: SIZEOF_INT * * OS Dependent - sizeof(int) */ rb_define_const(rb_mDL, "SIZEOF_INT", INT2NUM(sizeof(int))); /* Document-const: SIZEOF_LONG * * OS Dependent - sizeof(long) */ rb_define_const(rb_mDL, "SIZEOF_LONG", INT2NUM(sizeof(long))); #if HAVE_LONG_LONG /* Document-const: SIZEOF_LONG_LONG * * OS Dependent - sizeof(long long) */ rb_define_const(rb_mDL, "SIZEOF_LONG_LONG", INT2NUM(sizeof(LONG_LONG))); #endif /* Document-const: SIZEOF_FLOAT * * OS Dependent - sizeof(float) */ rb_define_const(rb_mDL, "SIZEOF_FLOAT", INT2NUM(sizeof(float))); /* Document-const: SIZEOF_DOUBLE * * OS Dependent - sizeof(double) */ rb_define_const(rb_mDL, "SIZEOF_DOUBLE",INT2NUM(sizeof(double))); rb_define_module_function(rb_mDL, "dlwrap", rb_dl_value2ptr, 1); rb_define_module_function(rb_mDL, "dlunwrap", rb_dl_ptr2value, 1); rb_define_module_function(rb_mDL, "dlopen", rb_dl_dlopen, -1); rb_define_module_function(rb_mDL, "malloc", rb_dl_malloc, 1); rb_define_module_function(rb_mDL, "realloc", rb_dl_realloc, 2); rb_define_module_function(rb_mDL, "free", rb_dl_free, 1); /* Document-const: RUBY_FREE * * Address of the ruby_xfree() function */ rb_define_const(rb_mDL, "RUBY_FREE", PTR2NUM(ruby_xfree)); /* Document-const: BUILD_RUBY_PLATFORM * * Platform built against (i.e. "x86_64-linux", etc.) * * See also RUBY_PLATFORM */ rb_define_const(rb_mDL, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM)); /* Document-const: BUILD_RUBY_VERSION * * Ruby Version built. (i.e. "1.9.3") * * See also RUBY_VERSION */ rb_define_const(rb_mDL, "BUILD_RUBY_VERSION", rb_str_new2(RUBY_VERSION)); Init_dlhandle(); Init_dlcfunc(); Init_dlptr(); }
/* * call-seq: Fiddle.dlwrap(val) * * Returns a memory pointer of a function's hexadecimal address location +val+ * * Example: * * lib = Fiddle.dlopen('/lib64/libc-2.15.so') * => #<Fiddle::Handle:0x00000001342460> * * Fiddle.dlwrap(lib['strcpy'].to_s(16)) * => 25522520 */ static VALUE rb_fiddle_value2ptr(VALUE self, VALUE val) { return PTR2NUM((void*)val); }