summaryrefslogtreecommitdiff
path: root/ext/ffi_c/FunctionInfo.c
diff options
context:
space:
mode:
authorWayne Meissner <wmeissner@gmail.com>2009-07-24 21:43:59 +1000
committerWayne Meissner <wmeissner@gmail.com>2009-07-24 21:43:59 +1000
commit79f92625d3722f2affa04d4ae9c2c4b5b22058cd (patch)
tree0eea9fb9b43759c79524a080175eb326fd4a11d8 /ext/ffi_c/FunctionInfo.c
parent0fdf58b6673fd27ab20542745ae8129acfbacc1c (diff)
downloadffi-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.c39
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) {