Ruby 1.9.3p327(2012-11-10revision37606)
|
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(_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 * Document-class: Fiddle::Function 00143 * 00144 * == Description 00145 * 00146 * A representation of a C function 00147 * 00148 * == Examples 00149 * 00150 * === 'strcpy' 00151 * 00152 * @libc = DL.dlopen "/lib/libc.so.6" 00153 * => #<DL::Handle:0x00000001d7a8d8> 00154 * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP) 00155 * => #<Fiddle::Function:0x00000001d8ee00> 00156 * buff = "000" 00157 * => "000" 00158 * str = f.call(buff, "123") 00159 * => #<DL::CPtr:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000> 00160 * str.to_s 00161 * => "123" 00162 * 00163 * === ABI check 00164 * 00165 * @libc = DL.dlopen "/lib/libc.so.6" 00166 * => #<DL::Handle:0x00000001d7a8d8> 00167 * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP) 00168 * => #<Fiddle::Function:0x00000001d8ee00> 00169 * f.abi == Fiddle::Function::DEFAULT 00170 * => true 00171 */ 00172 cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject); 00173 00174 /* 00175 * Document-const: DEFAULT 00176 * 00177 * Default ABI 00178 * 00179 */ 00180 rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI)); 00181 00182 #ifdef FFI_STDCALL 00183 /* 00184 * Document-const: STDCALL 00185 * 00186 * FFI implementation of WIN32 stdcall convention 00187 * 00188 */ 00189 rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL)); 00190 #endif 00191 00192 rb_define_alloc_func(cFiddleFunction, allocate); 00193 00194 /* 00195 * Document-method: call 00196 * 00197 * Calls the constructed Function, with +args+ 00198 * 00199 * For an example see Fiddle::Function 00200 * 00201 */ 00202 rb_define_method(cFiddleFunction, "call", function_call, -1); 00203 00204 /* 00205 * Document-method: new 00206 * call-seq: new(ptr, *args, ret_type, abi = DEFAULT) 00207 * 00208 * Constructs a Function object. 00209 * * +ptr+ is a referenced function, of a DL::Handle 00210 * * +args+ is an Array of arguments, passed to the +ptr+ function 00211 * * +ret_type+ is the return type of the function 00212 * * +abi+ is the ABI of the function 00213 * 00214 */ 00215 rb_define_method(cFiddleFunction, "initialize", initialize, -1); 00216 } 00217 /* vim: set noet sws=4 sw=4: */ 00218