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