@@ -103,7 +103,93 @@ cfunc_call(mrb_state *mrb, mrb_value self)
103
103
}
104
104
105
105
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
+
106
191
void init_cfunc_call (mrb_state * mrb , struct RClass * module )
107
192
{
108
193
mrb_define_class_method (mrb , module , "call" , cfunc_call , ARGS_ANY ());
194
+ mrb_define_module_function (mrb , module , "libcall" , cfunc_libcall , ARGS_ANY ());
109
195
}
0 commit comments