diff options
author | Wayne Meissner <wmeissner@gmail.com> | 2009-07-24 21:43:59 +1000 |
---|---|---|
committer | Wayne Meissner <wmeissner@gmail.com> | 2009-07-24 21:43:59 +1000 |
commit | 79f92625d3722f2affa04d4ae9c2c4b5b22058cd (patch) | |
tree | 0eea9fb9b43759c79524a080175eb326fd4a11d8 /ext/ffi_c/FunctionInfo.c | |
parent | 0fdf58b6673fd27ab20542745ae8129acfbacc1c (diff) | |
download | ffi-79f92625d3722f2affa04d4ae9c2c4b5b22058cd.tar.gz |
Handle callback parameter types, :enums and :convention options
Diffstat (limited to 'ext/ffi_c/FunctionInfo.c')
-rw-r--r-- | ext/ffi_c/FunctionInfo.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/ext/ffi_c/FunctionInfo.c b/ext/ffi_c/FunctionInfo.c index 16af599..123e4b8 100644 --- a/ext/ffi_c/FunctionInfo.c +++ b/ext/ffi_c/FunctionInfo.c @@ -39,7 +39,8 @@ fninfo_allocate(VALUE klass) fnInfo->type.alignment = ffi_type_pointer.alignment; fnInfo->type.nativeType = NATIVE_FUNCTION; fnInfo->rbReturnType = Qnil; - fnInfo->rbParameterTypes = NULL; + fnInfo->rbParameterTypes = Qnil; + fnInfo->rbEnums = Qnil; return obj; } @@ -49,6 +50,10 @@ fninfo_mark(FunctionInfo* fnInfo) { rb_gc_mark(fnInfo->rbReturnType); rb_gc_mark(fnInfo->rbParameterTypes); + rb_gc_mark(fnInfo->rbEnums); + if (fnInfo->callbackCount > 0 && fnInfo->callbackParameters != NULL) { + rb_gc_mark_locations(&fnInfo->callbackParameters[0], &fnInfo->callbackParameters[fnInfo->callbackCount]); + } } static void @@ -57,9 +62,19 @@ fninfo_free(FunctionInfo* fnInfo) if (fnInfo->parameterTypes != NULL) { xfree(fnInfo->parameterTypes); } + if (fnInfo->ffiParameterTypes != NULL) { xfree(fnInfo->ffiParameterTypes); } + + if (fnInfo->nativeParameterTypes != NULL) { + xfree(fnInfo->nativeParameterTypes); + } + + if (fnInfo->callbackParameters != NULL) { + xfree(fnInfo->callbackParameters); + } + xfree(fnInfo); } @@ -69,17 +84,24 @@ fninfo_initialize(int argc, VALUE* argv, VALUE self) FunctionInfo *fnInfo; ffi_status status; VALUE rbReturnType = Qnil, rbParamTypes = Qnil, rbOptions = Qnil; + VALUE rbEnums = Qnil, rbConvention = Qnil; 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"))); + } + Check_Type(rbParamTypes, T_ARRAY); Data_Get_Struct(self, FunctionInfo, 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; for (i = 0; i < fnInfo->parameterCount; ++i) { VALUE entry = rb_ary_entry(rbParamTypes, i); @@ -90,9 +112,15 @@ fninfo_initialize(int argc, VALUE* argv, VALUE self) rb_raise(rb_eTypeError, "Invalid parameter type (%s)", RSTRING_PTR(typeName)); } + if (rb_obj_is_kind_of(type, rbffi_FunctionInfoClass)) { + REALLOC_N(fnInfo->callbackParameters, VALUE, fnInfo->callbackCount + 1); + fnInfo->callbackParameters[fnInfo->callbackCount++] = type; + } + 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); @@ -104,11 +132,14 @@ fninfo_initialize(int argc, VALUE* argv, VALUE self) Data_Get_Struct(fnInfo->rbReturnType, Type, fnInfo->returnType); fnInfo->ffiReturnType = fnInfo->returnType->ffiType; -#if defined(_WIN32) && defined(notyet) - fnInfo->abi = (flags & STDCALL) ? FFI_STDCALL : FFI_DEFAULT_ABI; + +#if defined(_WIN32) || defined(__WIN32__) + fnInfo->abi = (rbConvention != Qnil && strcmp(StringValueCStr(rbConvention), "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) { |