• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/fiddle/function.c

Go to the documentation of this file.
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     /* const */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(HAVE_WINDOWS_H)
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     cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject);
00142 
00143     rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
00144 
00145 #ifdef FFI_STDCALL
00146     rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL));
00147 #endif
00148 
00149     rb_define_alloc_func(cFiddleFunction, allocate);
00150 
00151     rb_define_method(cFiddleFunction, "call", function_call, -1);
00152     rb_define_method(cFiddleFunction, "initialize", initialize, -1);
00153 }
00154 /* vim: set noet sws=4 sw=4: */
00155 

Generated on Wed Sep 8 2010 21:53:48 for Ruby by  doxygen 1.7.1