Ruby 1.9.2p136(2010-12-25revision30365)

- 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