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