Skip to content

Commit 323bbc9

Browse files
committed
Add libcall
1 parent 2809308 commit 323bbc9

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

src/cfunc_call.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,93 @@ cfunc_call(mrb_state *mrb, mrb_value self)
103103
}
104104

105105

106+
static mrb_value
107+
cfunc_libcall(mrb_state *mrb, mrb_value self)
108+
{
109+
int margc;
110+
mrb_value mresult_type, mlib, mname, *margs;
111+
void **values = NULL;
112+
ffi_type **args = NULL;
113+
114+
mrb_get_args(mrb, "oSo*", &mresult_type, &mlib, &mname, &margs, &margc);
115+
116+
void *fp = NULL;
117+
if((mrb_string_p(mname) || mrb_symbol_p(mname))) {
118+
void *dlh = dlopen(mrb_string_value_ptr(mrb, mlib), RTLD_LAZY);
119+
fp = dlsym(dlh, mrb_string_value_ptr(mrb, mname));
120+
dlclose(dlh);
121+
122+
if(fp == NULL) {
123+
mrb_raisef(mrb, E_NAME_ERROR, "can't find C function %s", mrb_string_value_ptr(mrb, mname));
124+
goto cfunc_call_exit;
125+
}
126+
}
127+
else {
128+
fp = cfunc_pointer_ptr(mname);
129+
if(fp == NULL) {
130+
mrb_raisef(mrb, E_NAME_ERROR, "can't call NULL pointer");
131+
goto cfunc_call_exit;
132+
}
133+
}
134+
135+
args = malloc(sizeof(ffi_type*) * margc);
136+
values = malloc(sizeof(void*) * margc);
137+
mrb_sym sym_to_ffi_value = mrb_intern(mrb, "to_ffi_value");
138+
139+
mrb_value nil_ary[1];
140+
nil_ary[0] = mrb_nil_value();
141+
int i;
142+
for(i = 0; i < margc; ++i) {
143+
if(mrb_respond_to(mrb, margs[i], sym_to_ffi_value)) {
144+
args[i] = mrb_value_to_mrb_ffi_type(mrb, margs[i])->ffi_type_value;
145+
values[i] = cfunc_pointer_ptr(mrb_funcall_argv(mrb, margs[i], sym_to_ffi_value, 1, nil_ary));
146+
}
147+
else {
148+
cfunc_mrb_raise_without_jump(mrb, E_TYPE_ERROR, "ignore argument type %s", mrb_obj_classname(mrb, margs[i]));
149+
goto cfunc_call_exit;
150+
}
151+
}
152+
153+
ffi_type *result_type = rclass_to_mrb_ffi_type(mrb, mrb_class_ptr(mresult_type))->ffi_type_value;
154+
if (result_type == NULL) {
155+
cfunc_mrb_raise_without_jump(mrb, E_ARGUMENT_ERROR, "ignore return type %s", mrb_class_name(mrb, mrb_class_ptr(mresult_type)));
156+
goto cfunc_call_exit;
157+
}
158+
159+
mrb_value mresult = mrb_nil_value();
160+
ffi_cif cif;
161+
if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, margc, result_type, args) == FFI_OK) {
162+
void *result;
163+
if(result_type->size > sizeof(long)) {
164+
result = malloc(result_type->size);
165+
}
166+
else if(result_type->size) {
167+
result = malloc(sizeof(long));
168+
}
169+
else {
170+
result = NULL;
171+
}
172+
ffi_call(&cif, fp, result, values);
173+
174+
if(result) {
175+
mrb_value result_ptr = cfunc_pointer_new_with_pointer(mrb, result, true);
176+
mresult = mrb_funcall(mrb, mresult_type, "refer", 1, result_ptr);
177+
}
178+
}
179+
else {
180+
mrb_raisef(mrb, E_NAME_ERROR, "Can't find C function %s", mname);
181+
goto cfunc_call_exit;
182+
}
183+
184+
cfunc_call_exit:
185+
free(values);
186+
free(args);
187+
return mresult;
188+
}
189+
190+
106191
void init_cfunc_call(mrb_state *mrb, struct RClass* module)
107192
{
108193
mrb_define_class_method(mrb, module, "call", cfunc_call, ARGS_ANY());
194+
mrb_define_module_function(mrb, module, "libcall", cfunc_libcall, ARGS_ANY());
109195
}

0 commit comments

Comments
 (0)