comparison ruby/rbdc/rbdc.c @ 0:0cfcc391201f

initial from svn dyncall-1745
author Daniel Adler
date Thu, 19 Mar 2015 22:26:28 +0100
parents
children 5e159be89d73
comparison
equal deleted inserted replaced
-1:000000000000 0:0cfcc391201f
1 /*
2
3 rbdc.c
4 Copyright (c) 2007-2014 Daniel Adler <dadler@uni-goettingen.de>,
5 Tassilo Philipp <tphilipp@potion-studios.com>
6
7 Permission to use, copy, modify, and distribute this software for any
8 purpose with or without fee is hereby granted, provided that the above
9 copyright notice and this permission notice appear in all copies.
10
11 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18
19 Ruby/dyncall extension implementation.
20
21 */
22
23
24 #include <ruby.h>
25 #include "../../../dyncall/dyncall/dyncall.h"
26 #include "../../../dyncall/dyncallback/dyncall_callback.h"
27 #include "../../../dyncall/dynload/dynload.h"
28 #include "../../../dyncall/dyncall/dyncall_signature.h"
29
30 /* Our ruby module and its classes. */
31 static VALUE rb_dcModule;
32 static VALUE rb_dcExtLib;
33
34
35 typedef struct {
36 void* lib;
37 void* syms;
38 DCCallVM* cvm;
39 } rb_dcLibHandle;
40
41
42 /* Allocator for handle and mark-and-sweep GC handlers. */
43 static void GCMark_ExtLib(rb_dcLibHandle* h)
44 {
45 }
46
47 static void GCSweep_ExtLib(rb_dcLibHandle* h)
48 {
49 if(h->lib != NULL) dlFreeLibrary(h->lib);
50 if(h->syms != NULL) dlSymsCleanup(h->syms);
51
52 dcFree(h->cvm);
53 free(h);
54 }
55
56 static VALUE AllocExtLib(VALUE cl)
57 {
58 rb_dcLibHandle* h = malloc(sizeof(rb_dcLibHandle));
59 h->lib = NULL;
60 h->syms = NULL;
61 h->cvm = dcNewCallVM(4096/*@@@*/);
62 return Data_Wrap_Struct(cl, GCMark_ExtLib, GCSweep_ExtLib, h);
63 }
64
65
66 /* Helpers */
67 static void ExtLib_SecCheckLib(rb_dcLibHandle* h)
68 {
69 if(h->lib == NULL)
70 rb_raise(rb_eRuntimeError, "no library loaded - use ExtLib#load");
71 }
72
73 static void ExtLib_SecCheckSyms(rb_dcLibHandle* h)
74 {
75 if(h->syms == NULL)
76 rb_raise(rb_eRuntimeError, "no symbol table initialized - use ExtLib#symsInit");
77 }
78
79
80
81 /* Methods for lib access */
82 static VALUE ExtLib_Load(VALUE self, VALUE path)
83 {
84 void* newLib;
85 rb_dcLibHandle* h;
86
87 if(TYPE(path) != T_STRING)
88 rb_raise(rb_eRuntimeError, "argument must be of type 'String'");/*@@@ respond to to_s*/
89
90 Data_Get_Struct(self, rb_dcLibHandle, h);
91 newLib = dlLoadLibrary(RSTRING_PTR(path));
92 if(newLib) {
93 dlFreeLibrary(h->lib);
94 h->lib = newLib;
95
96 return self;
97 }
98
99 return Qnil;
100 }
101
102 static VALUE ExtLib_ExistsQ(VALUE self, VALUE sym)
103 {
104 rb_dcLibHandle* h;
105
106 Data_Get_Struct(self, rb_dcLibHandle, h);
107 ExtLib_SecCheckLib(h);
108
109 return dlFindSymbol(h->lib, rb_id2name(SYM2ID(sym))) ? Qtrue : Qfalse;
110 }
111
112
113 /* Methods for syms parsing */
114 static VALUE ExtLib_SymsInit(VALUE self, VALUE path)
115 {
116 void* newSyms;
117 rb_dcLibHandle* h;
118
119 if(TYPE(path) != T_STRING)
120 rb_raise(rb_eRuntimeError, "argument must be of type 'String'");/*@@@ respond to to_s*/
121
122 Data_Get_Struct(self, rb_dcLibHandle, h);
123 newSyms = dlSymsInit(RSTRING_PTR(path));
124
125 if(newSyms) {
126 dlSymsCleanup(h->syms);
127 h->syms = newSyms;
128
129 return self;
130 }
131
132 return Qnil;
133 }
134
135
136 static VALUE ExtLib_SymsCount(VALUE self)
137 {
138 rb_dcLibHandle* h;
139
140 Data_Get_Struct(self, rb_dcLibHandle, h);
141 ExtLib_SecCheckSyms(h);
142
143 return LONG2NUM(dlSymsCount(h->syms));
144 }
145
146
147 static VALUE ExtLib_SymsEach(int argc, VALUE* argv, VALUE self)
148 {
149 rb_dcLibHandle* h;
150 size_t i, c;
151
152 if(!rb_block_given_p())
153 rb_raise(rb_eRuntimeError, "no block given");
154
155 Data_Get_Struct(self, rb_dcLibHandle, h);
156 ExtLib_SecCheckSyms(h);
157
158 c = dlSymsCount(h->syms);
159 for(i=0; i<c; ++i)
160 rb_yield(ID2SYM(rb_intern(dlSymsName(h->syms, i))));
161
162 return self;
163 }
164
165 /* expose dlSymsName @@@ */
166
167
168 /* Methods interfacing with dyncall */
169 static VALUE ExtLib_Call(int argc, VALUE* argv, VALUE self)
170 {
171 /* argv[0] - symbol to call *
172 * argv[1] - signature *
173 * argv[2] - first parameter *
174 * argv[x] - parameter x-2 */
175
176 rb_dcLibHandle* h;
177 DCpointer fptr;
178 int i, t, b;
179 VALUE r;
180 DCCallVM* cvm;
181 const char* sig;
182
183
184 /* Security checks. */
185 if(argc < 2)
186 rb_raise(rb_eRuntimeError, "wrong number of arguments for function call");
187
188 if(TYPE(argv[0]) != T_SYMBOL)
189 rb_raise(rb_eRuntimeError, "syntax error - argument 0 must be of type 'Symbol'");
190
191 if(TYPE(argv[1]) != T_STRING)
192 rb_raise(rb_eRuntimeError, "syntax error - argument 1 must be of type 'String'");
193
194 Data_Get_Struct(self, rb_dcLibHandle, h);
195 cvm = h->cvm;
196
197 if(argc != RSTRING_LEN(argv[1])) /* Don't count the return value in the signature @@@ write something more secure */
198 rb_raise(rb_eRuntimeError, "number of provided arguments doesn't match signature");
199
200 ExtLib_SecCheckLib(h);
201
202
203 /* Flush old arguments. */
204 dcReset(cvm);
205
206
207 /* Get a pointer to the function and start pushing. */
208 fptr = (DCpointer)dlFindSymbol(h->lib, rb_id2name(SYM2ID(argv[0])));
209 sig = RSTRING_PTR(argv[1]);
210
211 for(i=2; i<argc; ++i) {
212 t = TYPE(argv[i]);
213
214 //@@@ add support for calling convention mode(s)
215
216 switch(sig[i-2]) {
217 case DC_SIGCHAR_BOOL:
218 b = 1;
219 switch(t) {
220 case T_TRUE: dcArgBool(cvm, DC_TRUE); break; /* TrueClass. */
221 case T_FALSE: /* FalseClass. */
222 case T_NIL: dcArgBool(cvm, DC_FALSE); break; /* NilClass. */
223 case T_FIXNUM: dcArgBool(cvm, FIX2LONG(argv[i]) != 0); break; /* Fixnum. */
224 default: b = 0; break;
225 }
226 break;
227
228 case DC_SIGCHAR_CHAR:
229 case DC_SIGCHAR_UCHAR: if(b = (t == T_FIXNUM)) dcArgChar (cvm, (DCchar) FIX2LONG(argv[i])); break;
230 case DC_SIGCHAR_SHORT:
231 case DC_SIGCHAR_USHORT: if(b = (t == T_FIXNUM)) dcArgShort (cvm, (DCshort) FIX2LONG(argv[i])); break;
232 case DC_SIGCHAR_INT:
233 case DC_SIGCHAR_UINT: if(b = (t == T_FIXNUM)) dcArgInt (cvm, (DCint) FIX2LONG(argv[i])); break;
234 case DC_SIGCHAR_LONG:
235 case DC_SIGCHAR_ULONG: if(b = (t == T_FIXNUM)) dcArgLong (cvm, (DClong) FIX2LONG(argv[i])); break;
236 case DC_SIGCHAR_LONGLONG:
237 case DC_SIGCHAR_ULONGLONG: if(b = (t == T_FIXNUM)) dcArgLongLong(cvm, (DClonglong)FIX2LONG(argv[i])); break;
238 case DC_SIGCHAR_FLOAT: if(b = (t == T_FLOAT)) dcArgFloat (cvm, (DCfloat) RFLOAT_VALUE(argv[i])); break;
239 case DC_SIGCHAR_DOUBLE: if(b = (t == T_FLOAT)) dcArgDouble (cvm, (DCdouble) RFLOAT_VALUE(argv[i])); break;
240
241 case DC_SIGCHAR_POINTER:
242 case DC_SIGCHAR_STRING:
243 b = 1;
244 switch(t) {
245 case T_STRING: dcArgPointer(cvm, RSTRING_PTR(argv[i])); break; /* String. */
246 default: b = 0; break;
247 }
248 break;
249
250 default:
251 b = 0;
252 break;
253 }
254
255
256 if(!b)
257 rb_raise(rb_eRuntimeError, "syntax error in signature or type mismatch at argument %d", i-2);
258 }
259
260
261 /* Get the return type and call the function. */
262 switch(sig[i-1]) {
263 case DC_SIGCHAR_VOID: r = Qnil; dcCallVoid (cvm, fptr); break;
264 case DC_SIGCHAR_BOOL: r = dcCallBool (cvm, fptr) ? Qtrue : Qfalse; break;
265 case DC_SIGCHAR_CHAR:
266 case DC_SIGCHAR_UCHAR: r = CHR2FIX( dcCallChar (cvm, fptr)); break;
267 case DC_SIGCHAR_SHORT:
268 case DC_SIGCHAR_USHORT: r = INT2FIX( dcCallShort (cvm, fptr)); break;
269 case DC_SIGCHAR_INT:
270 case DC_SIGCHAR_UINT: r = INT2FIX( dcCallInt (cvm, fptr)); break;
271 case DC_SIGCHAR_LONG:
272 case DC_SIGCHAR_ULONG: r = INT2FIX( dcCallLong (cvm, fptr)); break;
273 case DC_SIGCHAR_LONGLONG:
274 case DC_SIGCHAR_ULONGLONG: r = INT2FIX( dcCallLongLong(cvm, fptr)); break;
275 case DC_SIGCHAR_FLOAT: r = rb_float_new(dcCallFloat (cvm, fptr)); break;
276 case DC_SIGCHAR_DOUBLE: r = rb_float_new(dcCallDouble (cvm, fptr)); break;
277 case DC_SIGCHAR_STRING: r = rb_str_new2( dcCallPointer (cvm, fptr)); break;
278 case DC_SIGCHAR_POINTER:
279 default:
280 rb_raise(rb_eRuntimeError, "unsupported return type or syntax error in signature");
281 }
282
283 return r;
284 }
285
286
287 /* Main initialization. */
288 void Init_rbdc()
289 {
290 rb_dcModule = rb_define_module("Dyncall");
291
292 /* Handle to the external dynamic library. */
293 rb_dcExtLib = rb_define_class_under(rb_dcModule, "ExtLib", rb_cObject);
294
295 /* Class allocators. */
296 rb_define_alloc_func(rb_dcExtLib, AllocExtLib);
297
298 /* Methods. */
299 rb_define_method(rb_dcExtLib, "load", &ExtLib_Load, 1);
300 rb_define_method(rb_dcExtLib, "exists?", &ExtLib_ExistsQ, 1);
301 rb_define_method(rb_dcExtLib, "syms_init", &ExtLib_SymsInit, 1);
302 rb_define_method(rb_dcExtLib, "syms_count", &ExtLib_SymsCount, 0);
303 rb_define_method(rb_dcExtLib, "syms_each", &ExtLib_SymsEach, -1);
304 rb_define_method(rb_dcExtLib, "call", &ExtLib_Call, -1);
305 }
306