Created
May 25, 2012 10:23
-
-
Save ammar/2787174 to your computer and use it in GitHub Desktop.
Examples of wrapping rb_funcall and rb_funcall2 with rb_rescue2.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define MY_FUNCALL_ARGC 3 | |
VALUE my_funcall(VALUE receiver, ID method_id, int argc, ...); | |
VALUE my_funcall_ex(VALUE data); | |
VALUE my_funcall2(VALUE receiver, ID method_id, int argc, VALUE *argv); | |
VALUE my_funcall2_ex(VALUE data); | |
// my_rescue: exception handler used by both of the wrappers below. | |
// ---------------------------------------------------------------------------- | |
static VALUE | |
my_rescue(VALUE data, VALUE exception) | |
{ | |
// do something... | |
} | |
// my_funcall: wraps calls to rb_funcall (or rb_funcall2, depending on argc) | |
// in a call to rb_rescue2. Catches any decesndant of rb_eException. | |
// ---------------------------------------------------------------------------- | |
VALUE | |
my_funcall(VALUE receiver, ID method_id, int argc, ...) | |
{ | |
va_list arg_list; | |
long argi; | |
VALUE *argv; | |
VALUE result = Qnil; | |
if( argc > 0 ) { | |
va_start(arg_list, argc); | |
argv = ALLOCA_N(VALUE, (argc + MY_FUNCALL_ARGC)); | |
argv[0] = argc; | |
argv[1] = receiver; | |
argv[2] = method_id; | |
for( argi = 0; argi < argc; argi++ ) { | |
argv[argi + MY_FUNCALL_ARGC] = va_arg(arg_list, VALUE); | |
} | |
va_end(arg_list); | |
} else { | |
argv = ALLOCA_N(VALUE, MY_FUNCALL_ARGC); | |
argv[0] = argc; | |
argv[1] = receiver; | |
argv[2] = method_id; | |
} | |
for( argi = 0; argi < (argc + MY_FUNCALL_ARGC); argi++ ) { | |
rb_gc_register_address(&argv[argi]); | |
} | |
result = rb_rescue2(RUBY_METHOD_FUNC(my_funcall_ex), (VALUE)argv, | |
RUBY_METHOD_FUNC(my_rescue), (VALUE)argv, | |
rb_eException, (VALUE) 0); | |
for( argi = 0; argi < (argc + MY_FUNCALL_ARGC); argi++ ) { | |
rb_gc_unregister_address(&argv[argi]); | |
} | |
return( result ); | |
} | |
// my_funcall_ex: the actual call to rb_funcall or rb_funcall2 to be made by | |
// my_funcall. | |
// ---------------------------------------------------------------------------- | |
static VALUE | |
my_funcall_ex(VALUE data) | |
{ | |
VALUE *args = (VALUE*) data; | |
if( args[0] > 0 ) { | |
return rb_funcall2(args[1], args[2], args[0], &args[3]); | |
} else { | |
return rb_funcall(args[1], args[2], args[0]); | |
} | |
} | |
// ---------------------------------------------------------------------------- | |
// my_funcall: wraps calls to rb_funcall2 in a call to rb_rescue2. Catches any | |
// decesndant of rb_eException. | |
// ---------------------------------------------------------------------------- | |
VALUE | |
my_funcall2(VALUE receiver, ID method_id, int argc, VALUE *argv) | |
{ | |
int argi = 0; | |
VALUE args[4]; | |
VALUE result; | |
args[0] = receiver; | |
args[1] = method_id; | |
args[2] = argc; | |
args[3] = (VALUE)argv; | |
for( argi = 0; argi <= MY_FUNCALL_ARGC; argi++ ) { | |
rb_gc_register_address(&args[argi]); | |
} | |
result = rb_rescue2(RUBY_METHOD_FUNC(my_funcall2_ex), (VALUE)&args[0], | |
RUBY_METHOD_FUNC(my_rescue), (VALUE)&args[0], | |
rb_eException, (VALUE) 0); | |
for( argi = MY_FUNCALL_ARGC; argi >= 0; argi-- ) { | |
rb_gc_unregister_address(&args[argi]); | |
} | |
return( result ); | |
} | |
// my_funcall2_ex: the actual call to rb_funcall2 to be made by my_funcall2. | |
// ---------------------------------------------------------------------------- | |
static VALUE | |
my_funcall2_ex(VALUE data) | |
{ | |
VALUE *args = (VALUE*) data; | |
return rb_funcall2(args[0], args[1], args[2], (VALUE*)args[3]); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment