Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

function.c
Go to the documentation of this file.
1 #include <fiddle.h>
2
3 VALUE cFiddleFunction;
4
5 static void
6 deallocate(void *p)
7 {
8 ffi_cif *ptr = p;
9 if (ptr->arg_types) xfree(ptr->arg_types);
10 xfree(ptr);
11 }
12
13 static size_t
14 function_memsize(const void *p)
15 {
16 /* const */ffi_cif *ptr = (ffi_cif *)p;
17 size_t size = 0;
18
19 if (ptr) {
20 size += sizeof(*ptr);
21 #if !defined(FFI_NO_RAW_API) || !FFI_NO_RAW_API
22 size += ffi_raw_size(ptr);
23 #endif
24 }
25 return size;
26 }
27
28 const rb_data_type_t function_data_type = {
29 "fiddle/function",
30 {0, deallocate, function_memsize,},
31 };
32
33 static VALUE
34 allocate(VALUE klass)
35 {
36 ffi_cif * cif;
37
38 return TypedData_Make_Struct(klass, ffi_cif, &function_data_type, cif);
39 }
40
41 VALUE
42 rb_fiddle_new_function(VALUE address, VALUE arg_types, VALUE ret_type)
43 {
44 VALUE argv[3];
45
46 argv[0] = address;
47 argv[1] = arg_types;
48 argv[2] = ret_type;
49
50 return rb_class_new_instance(3, argv, cFiddleFunction);
51 }
52
53 static int
54 parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
55 {
56 if (key == ID2SYM(rb_intern("name"))) {
57 rb_iv_set(self, "@name", value);
58 } else {
59 rb_raise(rb_eArgError, "unknown keyword: %"PRIsVALUE, key);
60 }
61 return ST_CONTINUE;
62 }
63
64 static VALUE
65 initialize(int argc, VALUE argv[], VALUE self)
66 {
67 ffi_cif * cif;
68 ffi_type **arg_types;
69 ffi_status result;
70 VALUE ptr, args, ret_type, abi, kwds;
71 int i;
72
73 rb_scan_args(argc, argv, "31:", &ptr, &args, &ret_type, &abi, &kwds);
74 if(NIL_P(abi)) abi = INT2NUM(FFI_DEFAULT_ABI);
75
76 Check_Type(args, T_ARRAY);
77
78 rb_iv_set(self, "@ptr", ptr);
79 rb_iv_set(self, "@args", args);
80 rb_iv_set(self, "@return_type", ret_type);
81 rb_iv_set(self, "@abi", abi);
82
83 if (!NIL_P(kwds)) rb_hash_foreach(kwds, parse_keyword_arg_i, self);
84
85 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
86
87 arg_types = xcalloc(RARRAY_LEN(args) + 1, sizeof(ffi_type *));
88
89 for (i = 0; i < RARRAY_LEN(args); i++) {
90 int type = NUM2INT(RARRAY_PTR(args)[i]);
91 arg_types[i] = INT2FFI_TYPE(type);
92 }
93 arg_types[RARRAY_LEN(args)] = NULL;
94
95 result = ffi_prep_cif (
96 cif,
97 NUM2INT(abi),
98 RARRAY_LENINT(args),
99 INT2FFI_TYPE(NUM2INT(ret_type)),
100 arg_types);
101
102 if (result)
103 rb_raise(rb_eRuntimeError, "error creating CIF %d", result);
104
105 return self;
106 }
107
108 static VALUE
109 function_call(int argc, VALUE argv[], VALUE self)
110 {
111 ffi_cif * cif;
112 fiddle_generic retval;
113 fiddle_generic *generic_args;
114 void **values;
115 VALUE cfunc, types, cPointer;
116 int i;
117
118 cfunc = rb_iv_get(self, "@ptr");
119 types = rb_iv_get(self, "@args");
120 cPointer = rb_const_get(mFiddle, rb_intern("Pointer"));
121
122 if(argc != RARRAY_LENINT(types)) {
123 rb_raise(rb_eArgError, "wrong number of arguments (%d for %d)",
124 argc, RARRAY_LENINT(types));
125 }
126
127 TypedData_Get_Struct(self, ffi_cif, &function_data_type, cif);
128
129 if (rb_safe_level() >= 1) {
130 for (i = 0; i < argc; i++) {
131 VALUE src = argv[i];
132 if (OBJ_TAINTED(src)) {
133 rb_raise(rb_eSecurityError, "tainted parameter not allowed");
134 }
135 }
136 }
137
138 values = xcalloc((size_t)argc + 1, (size_t)sizeof(void *));
139 generic_args = xcalloc((size_t)argc, (size_t)sizeof(fiddle_generic));
140
141 for (i = 0; i < argc; i++) {
142 VALUE type = RARRAY_PTR(types)[i];
143 VALUE src = argv[i];
144
145 if(NUM2INT(type) == TYPE_VOIDP) {
146 if(NIL_P(src)) {
147 src = INT2NUM(0);
148 } else if(cPointer != CLASS_OF(src)) {
149 src = rb_funcall(cPointer, rb_intern("[]"), 1, src);
150 }
151 src = rb_Integer(src);
152 }
153
154 VALUE2GENERIC(NUM2INT(type), src, &generic_args[i]);
155 values[i] = (void *)&generic_args[i];
156 }
157 values[argc] = NULL;
158
159 ffi_call(cif, NUM2PTR(rb_Integer(cfunc)), &retval, values);
160
161 rb_funcall(mFiddle, rb_intern("last_error="), 1, INT2NUM(errno));
162 #if defined(_WIN32)
163 rb_funcall(mFiddle, rb_intern("win32_last_error="), 1, INT2NUM(errno));
164 #endif
165
166 xfree(values);
167 xfree(generic_args);
168
169 return GENERIC2VALUE(rb_iv_get(self, "@return_type"), retval);
170 }
171
172 void
173 Init_fiddle_function(void)
174 {
175 /*
176 * Document-class: Fiddle::Function
177 *
178 * == Description
179 *
180 * A representation of a C function
181 *
182 * == Examples
183 *
184 * === 'strcpy'
185 *
186 * @libc = Fiddle.dlopen "/lib/libc.so.6"
187 * #=> #<Fiddle::Handle:0x00000001d7a8d8>
188 * f = Fiddle::Function.new(
189 * @libc['strcpy'],
190 * [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP],
191 * Fiddle::TYPE_VOIDP)
192 * #=> #<Fiddle::Function:0x00000001d8ee00>
193 * buff = "000"
194 * #=> "000"
195 * str = f.call(buff, "123")
196 * #=> #<Fiddle::Pointer:0x00000001d0c380 ptr=0x000000018a21b8 size=0 free=0x00000000000000>
197 * str.to_s
198 * => "123"
199 *
200 * === ABI check
201 *
202 * @libc = DL.dlopen "/lib/libc.so.6"
203 * #=> #<Fiddle::Handle:0x00000001d7a8d8>
204 * f = Fiddle::Function.new(@libc['strcpy'], [TYPE_VOIDP, TYPE_VOIDP], TYPE_VOIDP)
205 * #=> #<Fiddle::Function:0x00000001d8ee00>
206 * f.abi == Fiddle::Function::DEFAULT
207 * #=> true
208 */
209 cFiddleFunction = rb_define_class_under(mFiddle, "Function", rb_cObject);
210
211 /*
212 * Document-const: DEFAULT
213 *
214 * Default ABI
215 *
216 */
217 rb_define_const(cFiddleFunction, "DEFAULT", INT2NUM(FFI_DEFAULT_ABI));
218
219 #ifdef HAVE_CONST_FFI_STDCALL
220 /*
221 * Document-const: STDCALL
222 *
223 * FFI implementation of WIN32 stdcall convention
224 *
225 */
226 rb_define_const(cFiddleFunction, "STDCALL", INT2NUM(FFI_STDCALL));
227 #endif
228
229 rb_define_alloc_func(cFiddleFunction, allocate);
230
231 /*
232 * Document-method: call
233 *
234 * Calls the constructed Function, with +args+
235 *
236 * For an example see Fiddle::Function
237 *
238 */
239 rb_define_method(cFiddleFunction, "call", function_call, -1);
240
241 /*
242 * Document-method: new
243 * call-seq: new(ptr, args, ret_type, abi = DEFAULT)
244 *
245 * Constructs a Function object.
246 * * +ptr+ is a referenced function, of a Fiddle::Handle
247 * * +args+ is an Array of arguments, passed to the +ptr+ function
248 * * +ret_type+ is the return type of the function
249 * * +abi+ is the ABI of the function
250 *
251 */
252 rb_define_method(cFiddleFunction, "initialize", initialize, -1);
253 }
254 /* vim: set noet sws=4 sw=4: */
255