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 if (rb_safe_level() >= 1) {
00105 for (i = 0; i < argc; i++) {
00106 VALUE src = argv[i];
00107 if (OBJ_TAINTED(src)) {
00108 rb_raise(rb_eSecurityError, "tainted parameter not allowed");
00109 }
00110 }
00111 }
00112
00113 values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
00114 generic_args = xcalloc((size_t)argc, (size_t)sizeof(fiddle_generic));
00115
00116 for (i = 0; i < argc; i++) {
00117 VALUE type = RARRAY_PTR(types)[i];
00118 VALUE src = argv[i];
00119
00120 if(NUM2INT(type) == TYPE_VOIDP) {
00121 if(NIL_P(src)) {
00122 src = INT2NUM(0);
00123 } else if(cPointer != CLASS_OF(src)) {
00124 src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
00125 }
00126 src = rb_Integer(src);
00127 }
00128
00129 VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
00130 values[i] = (void *)&generic_args[i];
00131 }
00132 values[argc] = NULL;
00133
00134 ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
00135
00136 rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
00137 #if defined(_WIN32)
00138 rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
00139 #endif
00140
00141 xfree(values);
00142 xfree(generic_args);
00143
00144 return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
00145 }
00146
00147 void
00148 Init_fiddle_function(void)
00149 {
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject);
00182
00183
00184
00185
00186
00187
00188
00189 rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
00190
00191 #ifdef HAVE_CONST_FFI_STDCALL
00192
00193
00194
00195
00196
00197
00198 rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL));
00199 #endif
00200
00201 rb_define_alloc_func(cFiddleFunction, allocate);
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 rb_define_method(cFiddleFunction, "call", function_call, -1);
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224 rb_define_method(cFiddleFunction, "initialize", initialize, -1);
00225 }
00226
00227