00001 #include <fiddle.h>
00002
00003 VALUE cFiddleFunction;
00004
00005 static void
00006 deallocate(void *p)
00007 {
00008 ffi_cif *ptr = p;
00009 if (ptr->arg_types) xfree(ptr->arg_types);
00010 xfree(ptr);
00011 }
00012
00013 static size_t
00014 function_memsize(const void *p)
00015 {
00016 ffi_cif *ptr = (ffi_cif *)p;
00017 size_t size = 0;
00018
00019 if (ptr) {
00020 size += sizeof(*ptr);
00021 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
00022 size += ffi_raw_size(ptr);
00023 #endif
00024 }
00025 return size;
00026 }
00027
00028 const rb_data_type_t function_data_type = {
00029 "fiddle/function",
00030 {0, deallocate, function_memsize,},
00031 };
00032
00033 static VALUE
00034 allocate(VALUE klass)
00035 {
00036 ffi_cif * cif;
00037
00038 return TypedData_Make_Struct(klass, ffi_cif, &function_data_type, cif);
00039 }
00040
00041 static VALUE
00042 initialize(int argc, VALUE argv[], VALUE self)
00043 {
00044 ffi_cif * cif;
00045 ffi_type **arg_types;
00046 ffi_status result;
00047 VALUE ptr, args, ret_type, abi;
00048 int i;
00049
00050 rb_scan_args(argc, argv, "31", &ptr, &args, &ret_type, &abi);
00051 if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI);
00052
00053 Check_Type(args, T_ARRAY);
00054
00055 rb_iv_set(self, "@ptr", ptr);
00056 rb_iv_set(self, "@args", args);
00057 rb_iv_set(self, "@return_type", ret_type);
00058 rb_iv_set(self, "@abi", abi);
00059
00060 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
00061
00062 arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *));
00063
00064 for (i = 0; i < RARRAY_LEN(args); i++) {
00065 int type = NUM2INT(RARRAY_PTR(args)[i]);
00066 arg_types[i] = INT2FFI_TYPE(type);
00067 }
00068 arg_types[RARRAY_LEN(args)] = NULL;
00069
00070 result = ffi_prep_cif (
00071 cif,
00072 NUM2INT(abi),
00073 RARRAY_LENINT(args),
00074 INT2FFI_TYPE(NUM2INT(ret_type)),
00075 arg_types);
00076
00077 if (result)
00078 rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
00079
00080 return self;
00081 }
00082
00083 static VALUE
00084 function_call(int argc, VALUE argv[], VALUE self)
00085 {
00086 ffi_cif * cif;
00087 fiddle_generic retval;
00088 fiddle_generic *generic_args;
00089 void **values;
00090 VALUE cfunc, types, cPointer;
00091 int i;
00092
00093 cfunc = rb_iv_get(self, "@ptr");
00094 types = rb_iv_get(self, "@args");
00095 cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
00096
00097 if(argc != RARRAY_LENINT(types)) {
00098 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
00099 argc, RARRAY_LENINT(types));
00100 }
00101
00102 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
00103
00104 values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
00105 generic_args = xcalloc((size_t)argc, (size_t)sizeof(fiddle_generic));
00106
00107 for (i = 0; i < argc; i++) {
00108 VALUE type = RARRAY_PTR(types)[i];
00109 VALUE src = argv[i];
00110
00111 if(NUM2INT(type) == TYPE_VOIDP) {
00112 if(NIL_P(src)) {
00113 src = INT2NUM(0);
00114 } else if(cPointer != CLASS_OF(src)) {
00115 src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
00116 }
00117 src = rb_Integer(src);
00118 }
00119
00120 VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
00121 values[i] = (void *)&generic_args[i];
00122 }
00123 values[argc] = NULL;
00124
00125 ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
00126
00127 rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
00128 #if defined(_WIN32)
00129 rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
00130 #endif
00131
00132 xfree(values);
00133 xfree(generic_args);
00134
00135 return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
00136 }
00137
00138 void
00139 Init_fiddle_function(void)
00140 {
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject);
00173
00174
00175
00176
00177
00178
00179
00180 rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
00181
00182 #ifdef FFI_STDCALL
00183
00184
00185
00186
00187
00188
00189 rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL));
00190 #endif
00191
00192 rb_define_alloc_func(cFiddleFunction, allocate);
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 rb_define_method(cFiddleFunction, "call", function_call, -1);
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215 rb_define_method(cFiddleFunction, "initialize", initialize, -1);
00216 }
00217
00218