* file.c (rb_find_file_ext): guard load_path from GC.
[ruby-svn.git] / ext / dl / cfunc.c
blob22e8600002df0a84ad69ad5d78c2c8ea11469975
1 /* -*- C -*-
2 * $Id$
3 */
5 #include <ruby.h>
6 #include <errno.h>
7 #include "dl.h"
9 VALUE rb_cDLCFunc;
11 static ID id_last_error;
13 static VALUE
14 rb_dl_get_last_error(VALUE self)
16 return rb_thread_local_aref(rb_thread_current(), id_last_error);
19 static VALUE
20 rb_dl_set_last_error(VALUE self, VALUE val)
22 rb_thread_local_aset(rb_thread_current(), id_last_error, val);
23 return Qnil;
26 #if defined(HAVE_WINDOWS_H)
27 #include <windows.h>
28 static ID id_win32_last_error;
30 static VALUE
31 rb_dl_get_win32_last_error(VALUE self)
33 return rb_thread_local_aref(rb_thread_current(), id_win32_last_error);
36 static VALUE
37 rb_dl_set_win32_last_error(VALUE self, VALUE val)
39 rb_thread_local_aset(rb_thread_current(), id_win32_last_error, val);
40 return Qnil;
42 #endif
45 void
46 dlcfunc_free(struct cfunc_data *data)
48 if( data->name ){
49 xfree(data->name);
51 xfree(data);
54 VALUE
55 rb_dlcfunc_new(void (*func)(), int type, const char *name, ID calltype)
57 VALUE val;
58 struct cfunc_data *data;
60 rb_secure(4);
61 if( func ){
62 val = Data_Make_Struct(rb_cDLCFunc, struct cfunc_data, 0, dlcfunc_free, data);
63 data->ptr = func;
64 data->name = name ? strdup(name) : NULL;
65 data->type = type;
66 data->calltype = calltype;
68 else{
69 val = Qnil;
72 return val;
75 void *
76 rb_dlcfunc2ptr(VALUE val)
78 struct cfunc_data *data;
79 void * func;
81 if( rb_obj_is_kind_of(val, rb_cDLCFunc) ){
82 Data_Get_Struct(val, struct cfunc_data, data);
83 func = data->ptr;
85 else if( val == Qnil ){
86 func = NULL;
88 else{
89 rb_raise(rb_eTypeError, "DL::CFunc was expected");
92 return func;
95 VALUE
96 rb_dlcfunc_s_allocate(VALUE klass)
98 VALUE obj;
99 struct cfunc_data *data;
101 obj = Data_Make_Struct(klass, struct cfunc_data, 0, dlcfunc_free, data);
102 data->ptr = 0;
103 data->name = 0;
104 data->type = 0;
105 data->calltype = CFUNC_CDECL;
107 return obj;
110 VALUE
111 rb_dlcfunc_initialize(int argc, VALUE argv[], VALUE self)
113 VALUE addr, name, type, calltype;
114 struct cfunc_data *data;
115 void *saddr;
116 const char *sname;
118 rb_scan_args(argc, argv, "13", &addr, &type, &name, &calltype);
120 saddr = (void*)(NUM2PTR(rb_Integer(addr)));
121 sname = NIL_P(name) ? NULL : StringValuePtr(name);
123 Data_Get_Struct(self, struct cfunc_data, data);
124 if( data->name ) xfree(data->name);
125 data->ptr = saddr;
126 data->name = sname ? strdup(sname) : 0;
127 data->type = (type == Qnil) ? DLTYPE_VOID : NUM2INT(type);
128 data->calltype = (calltype == Qnil) ? CFUNC_CDECL : SYM2ID(calltype);
130 return Qnil;
133 VALUE
134 rb_dlcfunc_name(VALUE self)
136 struct cfunc_data *cfunc;
138 Data_Get_Struct(self, struct cfunc_data, cfunc);
139 return cfunc->name ? rb_tainted_str_new2(cfunc->name) : Qnil;
142 VALUE
143 rb_dlcfunc_ctype(VALUE self)
145 struct cfunc_data *cfunc;
147 Data_Get_Struct(self, struct cfunc_data, cfunc);
148 return INT2NUM(cfunc->type);
151 VALUE
152 rb_dlcfunc_set_ctype(VALUE self, VALUE ctype)
154 struct cfunc_data *cfunc;
156 Data_Get_Struct(self, struct cfunc_data, cfunc);
157 cfunc->type = NUM2INT(ctype);
158 return ctype;
161 VALUE
162 rb_dlcfunc_calltype(VALUE self)
164 struct cfunc_data *cfunc;
166 Data_Get_Struct(self, struct cfunc_data, cfunc);
167 return ID2SYM(cfunc->calltype);
170 VALUE
171 rb_dlcfunc_set_calltype(VALUE self, VALUE sym)
173 struct cfunc_data *cfunc;
175 Data_Get_Struct(self, struct cfunc_data, cfunc);
176 cfunc->calltype = SYM2ID(sym);
177 return sym;
181 VALUE
182 rb_dlcfunc_ptr(VALUE self)
184 struct cfunc_data *cfunc;
186 Data_Get_Struct(self, struct cfunc_data, cfunc);
187 return PTR2NUM(cfunc->ptr);
190 VALUE
191 rb_dlcfunc_set_ptr(VALUE self, VALUE addr)
193 struct cfunc_data *cfunc;
195 Data_Get_Struct(self, struct cfunc_data, cfunc);
196 cfunc->ptr = NUM2PTR(addr);
198 return Qnil;
201 VALUE
202 rb_dlcfunc_inspect(VALUE self)
204 VALUE val;
205 char *str;
206 int str_size;
207 struct cfunc_data *cfunc;
209 Data_Get_Struct(self, struct cfunc_data, cfunc);
211 str_size = (cfunc->name ? strlen(cfunc->name) : 0) + 100;
212 str = ruby_xmalloc(str_size);
213 snprintf(str, str_size - 1,
214 "#<DL::CFunc:%p ptr=%p type=%d name='%s'>",
215 cfunc,
216 cfunc->ptr,
217 cfunc->type,
218 cfunc->name ? cfunc->name : "");
219 val = rb_tainted_str_new2(str);
220 ruby_xfree(str);
222 return val;
226 # define DECL_FUNC_CDECL(f,ret,args) ret (FUNC_CDECL(*f))(args)
227 # define DECL_FUNC_STDCALL(f,ret,args) ret (FUNC_STDCALL(*f))(args)
229 #define CALL_CASE switch( RARRAY_LEN(ary) ){ \
230 CASE(0); break; \
231 CASE(1); break; CASE(2); break; CASE(3); break; CASE(4); break; CASE(5); break; \
232 CASE(6); break; CASE(7); break; CASE(8); break; CASE(9); break; CASE(10);break; \
233 CASE(11);break; CASE(12);break; CASE(13);break; CASE(14);break; CASE(15);break; \
234 CASE(16);break; CASE(17);break; CASE(18);break; CASE(19);break; CASE(20);break; \
235 default: rb_raise(rb_eArgError, "too many arguments"); \
239 VALUE
240 rb_dlcfunc_call(VALUE self, VALUE ary)
242 struct cfunc_data *cfunc;
243 int i;
244 DLSTACK_TYPE stack[DLSTACK_SIZE];
245 VALUE result = Qnil;
247 rb_secure_update(self);
249 memset(stack, 0, sizeof(DLSTACK_TYPE) * DLSTACK_SIZE);
250 Check_Type(ary, T_ARRAY);
252 Data_Get_Struct(self, struct cfunc_data, cfunc);
254 if( cfunc->ptr == 0 ){
255 rb_raise(rb_eDLError, "can't call null-function");
256 return Qnil;
259 for( i = 0; i < RARRAY_LEN(ary); i++ ){
260 if( i >= DLSTACK_SIZE ){
261 rb_raise(rb_eDLError, "too many arguments (stack overflow)");
263 stack[i] = NUM2LONG(RARRAY_PTR(ary)[i]);
266 /* calltype == CFUNC_CDECL */
267 if( cfunc->calltype == CFUNC_CDECL ){
268 switch( cfunc->type ){
269 case DLTYPE_VOID:
270 #define CASE(n) case n: { \
271 DECL_FUNC_CDECL(f,void,DLSTACK_PROTO##n) = cfunc->ptr; \
272 f(DLSTACK_ARGS##n(stack)); \
273 result = Qnil; \
275 CALL_CASE;
276 #undef CASE
277 break;
278 case DLTYPE_VOIDP:
279 #define CASE(n) case n: { \
280 DECL_FUNC_CDECL(f,void*,DLSTACK_PROTO##n) = cfunc->ptr; \
281 void * ret; \
282 ret = f(DLSTACK_ARGS##n(stack)); \
283 result = PTR2NUM(ret); \
285 CALL_CASE;
286 #undef CASE
287 break;
288 case DLTYPE_CHAR:
289 #define CASE(n) case n: { \
290 DECL_FUNC_CDECL(f,char,DLSTACK_PROTO##n) = cfunc->ptr; \
291 char ret; \
292 ret = f(DLSTACK_ARGS##n(stack)); \
293 result = CHR2FIX(ret); \
295 CALL_CASE;
296 #undef CASE
297 break;
298 case DLTYPE_SHORT:
299 #define CASE(n) case n: { \
300 DECL_FUNC_CDECL(f,short,DLSTACK_PROTO##n) = cfunc->ptr; \
301 short ret; \
302 ret = f(DLSTACK_ARGS##n(stack)); \
303 result = INT2NUM((int)ret); \
305 CALL_CASE;
306 #undef CASE
307 break;
308 case DLTYPE_INT:
309 #define CASE(n) case n: { \
310 DECL_FUNC_CDECL(f,int,DLSTACK_PROTO##n) = cfunc->ptr; \
311 int ret; \
312 ret = f(DLSTACK_ARGS##n(stack)); \
313 result = INT2NUM(ret); \
315 CALL_CASE;
316 #undef CASE
317 break;
318 case DLTYPE_LONG:
319 #define CASE(n) case n: { \
320 DECL_FUNC_CDECL(f,long,DLSTACK_PROTO##n) = cfunc->ptr; \
321 long ret; \
322 ret = f(DLSTACK_ARGS##n(stack)); \
323 result = LONG2NUM(ret); \
325 CALL_CASE;
326 #undef CASE
327 break;
328 #if HAVE_LONG_LONG /* used in ruby.h */
329 case DLTYPE_LONG_LONG:
330 #define CASE(n) case n: { \
331 DECL_FUNC_CDECL(f,LONG_LONG,DLSTACK_PROTO) = cfunc->ptr; \
332 LONG_LONG ret; \
333 ret = f(DLSTACK_ARGS(stack)); \
334 result = LL2NUM(ret); \
336 CALL_CASE;
337 #undef CASE
338 break;
339 #endif
340 case DLTYPE_FLOAT:
341 #define CASE(n) case n: { \
342 DECL_FUNC_CDECL(f,float,DLSTACK_PROTO) = cfunc->ptr; \
343 float ret; \
344 ret = f(DLSTACK_ARGS(stack)); \
345 result = rb_float_new(ret); \
347 CALL_CASE;
348 #undef CASE
349 break;
350 case DLTYPE_DOUBLE:
351 #define CASE(n) case n: { \
352 DECL_FUNC_CDECL(f,double,DLSTACK_PROTO) = cfunc->ptr; \
353 double ret; \
354 ret = f(DLSTACK_ARGS(stack)); \
355 result = rb_float_new(ret); \
357 CALL_CASE;
358 #undef CASE
359 break;
360 default:
361 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
364 else if( cfunc->calltype == CFUNC_STDCALL ){
365 /* calltype == CFUNC_STDCALL */
366 switch( cfunc->type ){
367 case DLTYPE_VOID:
368 #define CASE(n) case n: { \
369 DECL_FUNC_STDCALL(f,void,DLSTACK_PROTO##n) = cfunc->ptr; \
370 f(DLSTACK_ARGS##n(stack)); \
371 result = Qnil; \
373 CALL_CASE;
374 #undef CASE
375 break;
376 case DLTYPE_VOIDP:
377 #define CASE(n) case n: { \
378 DECL_FUNC_STDCALL(f,void*,DLSTACK_PROTO##n) = cfunc->ptr; \
379 void * ret; \
380 ret = f(DLSTACK_ARGS##n(stack)); \
381 result = PTR2NUM(ret); \
383 CALL_CASE;
384 #undef CASE
385 break;
386 case DLTYPE_CHAR:
387 #define CASE(n) case n: { \
388 DECL_FUNC_STDCALL(f,char,DLSTACK_PROTO##n) = cfunc->ptr; \
389 char ret; \
390 ret = f(DLSTACK_ARGS##n(stack)); \
391 result = CHR2FIX(ret); \
393 CALL_CASE;
394 #undef CASE
395 break;
396 case DLTYPE_SHORT:
397 #define CASE(n) case n: { \
398 DECL_FUNC_STDCALL(f,short,DLSTACK_PROTO##n) = cfunc->ptr; \
399 short ret; \
400 ret = f(DLSTACK_ARGS##n(stack)); \
401 result = INT2NUM((int)ret); \
403 CALL_CASE;
404 #undef CASE
405 break;
406 case DLTYPE_INT:
407 #define CASE(n) case n: { \
408 DECL_FUNC_STDCALL(f,int,DLSTACK_PROTO##n) = cfunc->ptr; \
409 int ret; \
410 ret = f(DLSTACK_ARGS##n(stack)); \
411 result = INT2NUM(ret); \
413 CALL_CASE;
414 #undef CASE
415 break;
416 case DLTYPE_LONG:
417 #define CASE(n) case n: { \
418 DECL_FUNC_STDCALL(f,long,DLSTACK_PROTO##n) = cfunc->ptr; \
419 long ret; \
420 ret = f(DLSTACK_ARGS##n(stack)); \
421 result = LONG2NUM(ret); \
423 CALL_CASE;
424 #undef CASE
425 break;
426 #if HAVE_LONG_LONG /* used in ruby.h */
427 case DLTYPE_LONG_LONG:
428 #define CASE(n) case n: { \
429 DECL_FUNC_STDCALL(f,LONG_LONG,DLSTACK_PROTO) = cfunc->ptr; \
430 LONG_LONG ret; \
431 ret = f(DLSTACK_ARGS(stack)); \
432 result = LL2NUM(ret); \
434 CALL_CASE;
435 #undef CASE
436 break;
437 #endif
438 case DLTYPE_FLOAT:
439 #define CASE(n) case n: { \
440 DECL_FUNC_STDCALL(f,float,DLSTACK_PROTO) = cfunc->ptr; \
441 float ret; \
442 ret = f(DLSTACK_ARGS(stack)); \
443 result = rb_float_new(ret); \
445 CALL_CASE;
446 #undef CASE
447 break;
448 case DLTYPE_DOUBLE:
449 #define CASE(n) case n: { \
450 DECL_FUNC_STDCALL(f,double,DLSTACK_PROTO) = cfunc->ptr; \
451 double ret; \
452 ret = f(DLSTACK_ARGS(stack)); \
453 result = rb_float_new(ret); \
455 CALL_CASE;
456 #undef CASE
457 break;
458 default:
459 rb_raise(rb_eDLTypeError, "unknown type %d", cfunc->type);
462 else{
463 rb_raise(rb_eDLError,
464 #ifndef LONG_LONG_VALUE
465 "unsupported call type: %lx",
466 #else
467 "unsupported call type: %llx",
468 #endif
469 cfunc->calltype);
472 rb_dl_set_last_error(self, INT2NUM(errno));
473 #if defined(HAVE_WINDOWS_H)
474 rb_dl_set_win32_last_error(self, INT2NUM(GetLastError()));
475 #endif
477 return result;
480 VALUE
481 rb_dlcfunc_to_i(VALUE self)
483 struct cfunc_data *cfunc;
485 Data_Get_Struct(self, struct cfunc_data, cfunc);
486 return PTR2NUM(cfunc->ptr);
489 void
490 Init_dlcfunc()
492 id_last_error = rb_intern("__DL2_LAST_ERROR__");
493 #if defined(HAVE_WINDOWS_H)
494 id_win32_last_error = rb_intern("__DL2_WIN32_LAST_ERROR__");
495 #endif
496 rb_cDLCFunc = rb_define_class_under(rb_mDL, "CFunc", rb_cObject);
497 rb_define_alloc_func(rb_cDLCFunc, rb_dlcfunc_s_allocate);
498 rb_define_module_function(rb_cDLCFunc, "last_error", rb_dl_get_last_error, 0);
499 #if defined(HAVE_WINDOWS_H)
500 rb_define_module_function(rb_cDLCFunc, "win32_last_error", rb_dl_get_win32_last_error, 0);
501 #endif
502 rb_define_method(rb_cDLCFunc, "initialize", rb_dlcfunc_initialize, -1);
503 rb_define_method(rb_cDLCFunc, "call", rb_dlcfunc_call, 1);
504 rb_define_method(rb_cDLCFunc, "[]", rb_dlcfunc_call, 1);
505 rb_define_method(rb_cDLCFunc, "name", rb_dlcfunc_name, 0);
506 rb_define_method(rb_cDLCFunc, "ctype", rb_dlcfunc_ctype, 0);
507 rb_define_method(rb_cDLCFunc, "ctype=", rb_dlcfunc_set_ctype, 1);
508 rb_define_method(rb_cDLCFunc, "calltype", rb_dlcfunc_calltype, 0);
509 rb_define_method(rb_cDLCFunc, "calltype=", rb_dlcfunc_set_calltype, 1);
510 rb_define_method(rb_cDLCFunc, "ptr", rb_dlcfunc_ptr, 0);
511 rb_define_method(rb_cDLCFunc, "ptr=", rb_dlcfunc_set_ptr, 1);
512 rb_define_method(rb_cDLCFunc, "inspect", rb_dlcfunc_inspect, 0);
513 rb_define_method(rb_cDLCFunc, "to_s", rb_dlcfunc_inspect, 0);
514 rb_define_method(rb_cDLCFunc, "to_i", rb_dlcfunc_to_i, 0);