static VALUE variadic_initialize(VALUE self, VALUE rbFunction, VALUE rbParameterTypes, VALUE rbReturnType, VALUE options) { VariadicInvoker* invoker = NULL; VALUE retval = Qnil; VALUE convention = Qnil; VALUE fixed = Qnil; VALUE rbConventionStr; int i; Check_Type(options, T_HASH); convention = rb_hash_aref(options, ID2SYM(rb_intern("convention"))); Data_Get_Struct(self, VariadicInvoker, invoker); invoker->rbEnums = rb_hash_aref(options, ID2SYM(rb_intern("enums"))); invoker->rbAddress = rbFunction; invoker->function = rbffi_AbstractMemory_Cast(rbFunction, rbffi_PointerClass)->address; #if defined(_WIN32) || defined(__WIN32__) rbConventionStr = rb_funcall2(convention, rb_intern("to_s"), 0, NULL); invoker->abi = (RTEST(convention) && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0) ? FFI_STDCALL : FFI_DEFAULT_ABI; #else invoker->abi = FFI_DEFAULT_ABI; #endif invoker->rbReturnType = rbffi_Type_Lookup(rbReturnType); if (!RTEST(invoker->rbReturnType)) { VALUE typeName = rb_funcall2(rbReturnType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid return type (%s)", RSTRING_PTR(typeName)); } Data_Get_Struct(rbReturnType, Type, invoker->returnType); invoker->paramCount = -1; fixed = rb_ary_new2(RARRAY_LEN(rbParameterTypes) - 1); for (i = 0; i < RARRAY_LEN(rbParameterTypes); ++i) { VALUE entry = rb_ary_entry(rbParameterTypes, i); VALUE rbType = rbffi_Type_Lookup(entry); Type* type; if (!RTEST(rbType)) { VALUE typeName = rb_funcall2(entry, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid parameter type (%s)", RSTRING_PTR(typeName)); } Data_Get_Struct(rbType, Type, type); if (type->nativeType != NATIVE_VARARGS) { rb_ary_push(fixed, entry); } } /* * @fixed and @type_map are used by the parameter mangling ruby code */ rb_iv_set(self, "@fixed", fixed); rb_iv_set(self, "@type_map", rb_hash_aref(options, ID2SYM(rb_intern("type_map")))); return retval; }
/** * rbffi_Type_Find() is like rbffi_Type_Lookup, but an error is raised if the * type is not found. */ VALUE rbffi_Type_Find(VALUE name) { VALUE rbType = rbffi_Type_Lookup(name); if (!RTEST(rbType)) { VALUE typeName = rb_funcall2(name, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid type (%s)", RSTRING_PTR(typeName)); } return rbType; }
/** * rbffi_Type_Find() is like rbffi_Type_Lookup, but an error is raised if the * type is not found. */ VALUE rbffi_Type_Find(VALUE name) { VALUE rbType = rbffi_Type_Lookup(name); if (!RTEST(rbType)) { VALUE s = rb_inspect(name); rb_raise(rb_eTypeError, "invalid type, %s", RSTRING_PTR(s)); RB_GC_GUARD(s); } return rbType; }
static VALUE fntype_initialize(int argc, VALUE* argv, VALUE self) { FunctionType *fnInfo; ffi_status status; VALUE rbReturnType = Qnil, rbParamTypes = Qnil, rbOptions = Qnil; VALUE rbEnums = Qnil, rbConvention = Qnil, rbBlocking = Qnil; #if defined(_WIN32) || defined(__WIN32__) VALUE rbConventionStr; #endif int i, nargs; nargs = rb_scan_args(argc, argv, "21", &rbReturnType, &rbParamTypes, &rbOptions); if (nargs >= 3 && rbOptions != Qnil) { rbConvention = rb_hash_aref(rbOptions, ID2SYM(rb_intern("convention"))); rbEnums = rb_hash_aref(rbOptions, ID2SYM(rb_intern("enums"))); rbBlocking = rb_hash_aref(rbOptions, ID2SYM(rb_intern("blocking"))); } Check_Type(rbParamTypes, T_ARRAY); Data_Get_Struct(self, FunctionType, fnInfo); fnInfo->parameterCount = RARRAY_LEN(rbParamTypes); fnInfo->parameterTypes = xcalloc(fnInfo->parameterCount, sizeof(*fnInfo->parameterTypes)); fnInfo->ffiParameterTypes = xcalloc(fnInfo->parameterCount, sizeof(ffi_type *)); fnInfo->nativeParameterTypes = xcalloc(fnInfo->parameterCount, sizeof(*fnInfo->nativeParameterTypes)); fnInfo->rbParameterTypes = rb_ary_new2(fnInfo->parameterCount); fnInfo->rbEnums = rbEnums; fnInfo->blocking = RTEST(rbBlocking); fnInfo->hasStruct = false; for (i = 0; i < fnInfo->parameterCount; ++i) { VALUE entry = rb_ary_entry(rbParamTypes, i); VALUE type = rbffi_Type_Lookup(entry); if (!RTEST(type)) { VALUE typeName = rb_funcall2(entry, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid parameter type (%s)", RSTRING_PTR(typeName)); } if (rb_obj_is_kind_of(type, rbffi_FunctionTypeClass)) { REALLOC_N(fnInfo->callbackParameters, VALUE, fnInfo->callbackCount + 1); fnInfo->callbackParameters[fnInfo->callbackCount++] = type; } if (rb_obj_is_kind_of(type, rbffi_StructByValueClass)) { fnInfo->hasStruct = true; } rb_ary_push(fnInfo->rbParameterTypes, type); Data_Get_Struct(type, Type, fnInfo->parameterTypes[i]); fnInfo->ffiParameterTypes[i] = fnInfo->parameterTypes[i]->ffiType; fnInfo->nativeParameterTypes[i] = fnInfo->parameterTypes[i]->nativeType; } fnInfo->rbReturnType = rbffi_Type_Lookup(rbReturnType); if (!RTEST(fnInfo->rbReturnType)) { VALUE typeName = rb_funcall2(rbReturnType, rb_intern("inspect"), 0, NULL); rb_raise(rb_eTypeError, "Invalid return type (%s)", RSTRING_PTR(typeName)); } if (rb_obj_is_kind_of(fnInfo->rbReturnType, rbffi_StructByValueClass)) { fnInfo->hasStruct = true; } Data_Get_Struct(fnInfo->rbReturnType, Type, fnInfo->returnType); fnInfo->ffiReturnType = fnInfo->returnType->ffiType; #if defined(_WIN32) || defined(__WIN32__) rbConventionStr = (rbConvention != Qnil) ? rb_funcall2(rbConvention, rb_intern("to_s"), 0, NULL) : Qnil; fnInfo->abi = (rbConventionStr != Qnil && strcmp(StringValueCStr(rbConventionStr), "stdcall") == 0) ? FFI_STDCALL : FFI_DEFAULT_ABI; #else fnInfo->abi = FFI_DEFAULT_ABI; #endif status = ffi_prep_cif(&fnInfo->ffi_cif, fnInfo->abi, fnInfo->parameterCount, fnInfo->ffiReturnType, fnInfo->ffiParameterTypes); switch (status) { case FFI_BAD_ABI: rb_raise(rb_eArgError, "Invalid ABI specified"); case FFI_BAD_TYPEDEF: rb_raise(rb_eArgError, "Invalid argument type specified"); case FFI_OK: break; default: rb_raise(rb_eArgError, "Unknown FFI error"); } fnInfo->invoke = rbffi_GetInvoker(fnInfo); return self; }