|
Ruby
2.0.0p481(2014-05-08revision45883)
|
00001 #include <fiddle.h> 00002 00003 #ifdef PRIsVALUE 00004 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj) 00005 # define RB_OBJ_STRING(obj) (obj) 00006 #else 00007 # define PRIsVALUE "s" 00008 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj) 00009 # define RB_OBJ_STRING(obj) StringValueCStr(obj) 00010 #endif 00011 00012 VALUE cFiddleFunction; 00013 00014 static void 00015 deallocate(void *p) 00016 { 00017 ffi_cif *ptr = p; 00018 if (ptr->arg_types) xfree(ptr->arg_types); 00019 xfree(ptr); 00020 } 00021 00022 static size_t 00023 function_memsize(const void *p) 00024 { 00025 /* const */ffi_cif *ptr = (ffi_cif *)p; 00026 size_t size = 0; 00027 00028 if (ptr) { 00029 size += sizeof(*ptr); 00030 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API 00031 size += ffi_raw_size(ptr); 00032 #endif 00033 } 00034 return size; 00035 } 00036 00037 const rb_data_type_t function_data_type = { 00038 "fiddle/function", 00039 {0, deallocate, function_memsize,}, 00040 }; 00041 00042 static VALUE 00043 allocate(VALUE klass) 00044 { 00045 ffi_cif * cif; 00046 00047 return TypedData_Make_Struct(klass, ffi_cif, &function_data_type, cif); 00048 } 00049 00050 VALUE 00051 rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type) 00052 { 00053 VALUE argv[3]; 00054 00055 argv[0] = address; 00056 argv[1] = arg_types; 00057 argv[2] = ret_type; 00058 00059 return rb_class_new_instance(3, argv, cFiddleFunction); 00060 } 00061 00062 static int 00063 parse_keyword_arg_i(VALUE key, VALUE value, VALUE self) 00064 { 00065 if (key == ID2SYM(rb_intern("name"))) { 00066 rb_iv_set(self, "@name", value); 00067 } else { 00068 rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, 00069 RB_OBJ_STRING(key)); 00070 } 00071 return ST_CONTINUE; 00072 } 00073 00074 static VALUE 00075 initialize(int argc, VALUE argv[], VALUE self) 00076 { 00077 ffi_cif * cif; 00078 ffi_type **arg_types; 00079 ffi_status result; 00080 VALUE ptr, args, ret_type, abi, kwds; 00081 int i; 00082 00083 rb_scan_args(argc, argv, "31:", &ptr, &args, &ret_type, &abi, &kwds); 00084 if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI); 00085 00086 Check_Type(args, T_ARRAY); 00087 00088 rb_iv_set(self, "@ptr", ptr); 00089 rb_iv_set(self, "@args", args); 00090 rb_iv_set(self, "@return_type", ret_type); 00091 rb_iv_set(self, "@abi", abi); 00092 00093 if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self); 00094 00095 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif); 00096 00097 arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *)); 00098 00099 for (i = 0; i < RARRAY_LEN(args); i++) { 00100 int type = NUM2INT(RARRAY_PTR(args)[i]); 00101 arg_types[i] = INT2FFI_TYPE(type); 00102 } 00103 arg_types[RARRAY_LEN(args)] = NULL; 00104 00105 result = ffi_prep_cif ( 00106 cif, 00107 NUM2INT(abi), 00108 RARRAY_LENINT(args), 00109 INT2FFI_TYPE(NUM2INT(ret_type)), 00110 arg_types); 00111 00112 if (result) 00113 rb_raise(rb_eRuntimeError, "error creating CIF %d", result); 00114 00115 return self; 00116 } 00117 00118 static VALUE 00119 function_call(int argc, VALUE argv[], VALUE self) 00120 { 00121 ffi_cif * cif; 00122 fiddle_generic retval; 00123 fiddle_generic *generic_args; 00124 void **values; 00125 VALUE cfunc, types, cPointer; 00126 int i; 00127 00128 cfunc = rb_iv_get(self, "@ptr"); 00129 types = rb_iv_get(self, "@args"); 00130 cPointer = rb_const_get(mFiddle, rb_intern("Pointer")); 00131 00132 if(argc != RARRAY_LENINT(types)) { 00133 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)", 00134 argc, RARRAY_LENINT(types)); 00135 } 00136 00137 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif); 00138 00139 if (rb_safe_level() >= 1) { 00140 for (i = 0; i < argc; i++) { 00141 VALUE src = argv[i]; 00142 if (OBJ_TAINTED(src)) { 00143 rb_raise(rb_eSecurityError, "tainted parameter not allowed"); 00144 } 00145 } 00146 } 00147 00148 values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *)); 00149 generic_args = xcalloc((size_t)argc, (size_t)sizeof(fiddle_generic)); 00150 00151 for (i = 0; i < argc; i++) { 00152 VALUE type = RARRAY_PTR(types)[i]; 00153 VALUE src = argv[i]; 00154 00155 if(NUM2INT(type) == TYPE_VOIDP) { 00156 if(NIL_P(src)) { 00157 src = INT2NUM(0); 00158 } else if(cPointer != CLASS_OF(src)) { 00159 src = rb_funcall(cPointer, rb_intern("[]"), 1, src); 00160 } 00161 src = rb_Integer(src); 00162 } 00163 00164 VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]); 00165 values[i] = (void *)&generic_args[i]; 00166 } 00167 values[argc] = NULL; 00168 00169 ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values); 00170 00171 rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno)); 00172 #if defined(_WIN32) 00173 rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno)); 00174 #endif 00175 00176 xfree(values); 00177 xfree(generic_args); 00178 00179 return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval); 00180 } 00181 00182 void 00183 Init_fiddle_function(void) 00184 { 00185 /* 00186 * Document-class: Fiddle::Function 00187 * 00188 * == Description 00189 * 00190 * A representation of a C function 00191 * 00192 * == Examples 00193 * 00194 * === 'strcpy' 00195 * 00196 * @libc = Fiddle.dlopen "/lib/libc.so.6" 00197 * #=> #<Fiddle::Handle:0x00000001d7a8d8> 00198 * f = Fiddle::Function.new( 00199 * @libc['strcpy'], 00200 * [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], 00201 * Fiddle::TYPE_VOIDP) 00202 * #=> #<Fiddle::Function:0x00000001d8ee00> 00203 * buff = "000" 00204 * #=> "000" 00205 * str = f.call(buff, "123") 00206 * #=> #<Fiddle::Pointer:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000> 00207 * str.to_s 00208 * => "123" 00209 * 00210 * === ABI check 00211 * 00212 * @libc = DL.dlopen "/lib/libc.so.6" 00213 * #=> #<Fiddle::Handle:0x00000001d7a8d8> 00214 * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP) 00215 * #=> #<Fiddle::Function:0x00000001d8ee00> 00216 * f.abi == Fiddle::Function::DEFAULT 00217 * #=> true 00218 */ 00219 cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject); 00220 00221 /* 00222 * Document-const: DEFAULT 00223 * 00224 * Default ABI 00225 * 00226 */ 00227 rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI)); 00228 00229 #ifdef HAVE_CONST_FFI_STDCALL 00230 /* 00231 * Document-const: STDCALL 00232 * 00233 * FFI implementation of WIN32 stdcall convention 00234 * 00235 */ 00236 rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL)); 00237 #endif 00238 00239 rb_define_alloc_func(cFiddleFunction, allocate); 00240 00241 /* 00242 * Document-method: call 00243 * 00244 * Calls the constructed Function, with +args+ 00245 * 00246 * For an example see Fiddle::Function 00247 * 00248 */ 00249 rb_define_method(cFiddleFunction, "call", function_call, -1); 00250 00251 /* 00252 * Document-method: new 00253 * call-seq: new(ptr, args, ret_type, abi = DEFAULT) 00254 * 00255 * Constructs a Function object. 00256 * * +ptr+ is a referenced function, of a Fiddle::Handle 00257 * * +args+ is an Array of arguments, passed to the +ptr+ function 00258 * * +ret_type+ is the return type of the function 00259 * * +abi+ is the ABI of the function 00260 * 00261 */ 00262 rb_define_method(cFiddleFunction, "initialize", initialize, -1); 00263 } 00264 /* vim: set noet sws=4 sw=4: */ 00265
1.7.6.1