Mercurial > pub > dyncall > bindings
comparison erlang/erldc/c_src/dyncallnif.c @ 0:0cfcc391201f
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:26:28 +0100 |
parents | |
children | 8070dae59227 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:0cfcc391201f |
---|---|
1 /* | |
2 Copyright (c) 2014 Erik Mackdanz <erikmack@gmail.com> | |
3 | |
4 Permission to use, copy, modify, and distribute this software for any | |
5 purpose with or without fee is hereby granted, provided that the above | |
6 copyright notice and this permission notice appear in all copies. | |
7 | |
8 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
15 */ | |
16 | |
17 #include "erl_nif.h" | |
18 #include "dyncall/dyncall.h" | |
19 #include "dyncall/dyncall_signature.h" | |
20 | |
21 #include <string.h> | |
22 #include <stdio.h> | |
23 | |
24 /************ Begin NIF initialization *******/ | |
25 | |
26 #define MAX_LIBPATH_SZ 128 | |
27 #define MAX_SYMBOL_NAME_SZ 32 | |
28 #define MAX_FORMAT_STRING_SZ 100 | |
29 #define MAX_STRING_ARG_SZ 1024 | |
30 | |
31 ErlNifResourceType *g_ptrrestype, *g_vmrestype; | |
32 | |
33 static void noop_dtor(ErlNifEnv* env, void* obj) { | |
34 // When erlang gc's a ptr, no-op since we can't know how to free it. | |
35 // Likewise with symbols, etc. | |
36 } | |
37 static void vm_dtor(ErlNifEnv* env, void* obj) { | |
38 void** ptr = (void**)obj; | |
39 dcFree(*ptr); | |
40 } | |
41 | |
42 static int nifload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { | |
43 | |
44 // Allows us to have a native pointer (to vm, lib, symbol, or user-defined) and | |
45 // pass a safe opaque handle into erlang | |
46 g_ptrrestype = enif_open_resource_type(env,"dyncall","pointer", | |
47 noop_dtor,ERL_NIF_RT_CREATE, | |
48 NULL); | |
49 | |
50 // Works like g_ptrrestype, but requires a dtor that calls dcFree | |
51 g_vmrestype = enif_open_resource_type(env,"dyncall","vmpointer", | |
52 vm_dtor,ERL_NIF_RT_CREATE, | |
53 NULL); | |
54 | |
55 return 0; | |
56 } | |
57 | |
58 /************ End NIF initialization *******/ | |
59 | |
60 #define ATOM_OK "ok" | |
61 #define ATOM_ERROR "error" | |
62 | |
63 #define ATOM_LIB_NOT_FOUND "lib_not_found" | |
64 #define ATOM_SYMBOL_NOT_FOUND "symbol_not_found" | |
65 #define ATOM_BADSZ "bad_vm_size" | |
66 #define ATOM_INVALID_VM "invalid_vm" | |
67 #define ATOM_INVALID_LIB "invalid_lib" | |
68 #define ATOM_INVALID_SYMBOL "invalid_symbol" | |
69 #define ATOM_INVALID_FORMAT "invalid_format" | |
70 #define ATOM_INVALID_ARG "invalid_arg" | |
71 #define ATOM_NOT_IMPLEMENTED "not_implemented" | |
72 | |
73 static ERL_NIF_TERM new_call_vm(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
74 | |
75 long vmsz = 0; | |
76 if(!enif_get_long(env, argv[0], &vmsz)) { | |
77 return enif_make_tuple2(env, | |
78 enif_make_atom(env,ATOM_ERROR), | |
79 enif_make_atom(env,ATOM_BADSZ) | |
80 ); | |
81 } | |
82 | |
83 DCCallVM* vm = dcNewCallVM( vmsz ); | |
84 | |
85 size_t sz = sizeof(DCCallVM*); | |
86 DCpointer ptr_persistent_vm = enif_alloc_resource(g_vmrestype,sz); | |
87 memcpy(ptr_persistent_vm,&vm,sz); | |
88 ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_vm); | |
89 enif_release_resource(ptr_persistent_vm); | |
90 | |
91 return enif_make_tuple2(env, | |
92 enif_make_atom(env,ATOM_OK), | |
93 retterm | |
94 ); | |
95 } | |
96 | |
97 #define MAYBE_RET_BAD_STRING_ARG(indexvar,argi,limit,retatom) \ | |
98 char indexvar[limit]; \ | |
99 indexvar[limit-1] = 0; \ | |
100 if(enif_get_string(env, argv[argi], indexvar, limit, ERL_NIF_LATIN1) <= 0) { \ | |
101 return enif_make_tuple2(env, \ | |
102 enif_make_atom(env,ATOM_ERROR), \ | |
103 enif_make_atom(env,retatom) \ | |
104 ); \ | |
105 } | |
106 | |
107 #define RETURN_ERROR(code) return enif_make_tuple2(env, \ | |
108 enif_make_atom(env,ATOM_ERROR), \ | |
109 enif_make_atom(env,code) \ | |
110 ); | |
111 | |
112 static ERL_NIF_TERM load_library(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
113 MAYBE_RET_BAD_STRING_ARG(path,0,MAX_LIBPATH_SZ,ATOM_INVALID_LIB) | |
114 | |
115 void* libptr = enif_dlopen(path, NULL, NULL); | |
116 | |
117 // Error if dlLoadLibrary returned NULL | |
118 if(!libptr) RETURN_ERROR(ATOM_LIB_NOT_FOUND) | |
119 | |
120 size_t sz = sizeof(void*); | |
121 DCpointer ptr_persistent_lib = enif_alloc_resource(g_ptrrestype,sz); | |
122 memcpy(ptr_persistent_lib,&libptr,sz); | |
123 ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_lib); | |
124 enif_release_resource(ptr_persistent_lib); | |
125 | |
126 return enif_make_tuple2(env, | |
127 enif_make_atom(env,ATOM_OK), | |
128 retterm | |
129 ); | |
130 } | |
131 | |
132 static ERL_NIF_TERM find_symbol(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
133 MAYBE_RET_BAD_STRING_ARG(path,1,MAX_SYMBOL_NAME_SZ,ATOM_INVALID_SYMBOL) | |
134 | |
135 void** libptr; | |
136 if(!enif_get_resource(env, argv[0], g_ptrrestype, (void**)&libptr)) RETURN_ERROR(ATOM_INVALID_LIB) | |
137 | |
138 void* symptr = enif_dlsym(*libptr,path,NULL,NULL); | |
139 | |
140 size_t sz = sizeof(void*); | |
141 DCpointer ptr_persistent_symbol = enif_alloc_resource(g_ptrrestype,sz); | |
142 memcpy(ptr_persistent_symbol,&symptr,sz); | |
143 ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_symbol); | |
144 enif_release_resource(ptr_persistent_symbol); | |
145 | |
146 // Error if enif_dlsym returned NULL | |
147 if(!symptr) RETURN_ERROR(ATOM_SYMBOL_NOT_FOUND) | |
148 | |
149 return enif_make_tuple2(env, | |
150 enif_make_atom(env,ATOM_OK), | |
151 retterm | |
152 ); | |
153 } | |
154 | |
155 #define BOOL_BUF_SZ 6 | |
156 #define ATOM_TRUE "true" | |
157 #define ATOM_FALSE "false" | |
158 | |
159 static void exec_call(ErlNifEnv* env, void* vm, void* sym, char rettype,ERL_NIF_TERM *retvalue, char** error_atom) { | |
160 if(!sym) { | |
161 *error_atom = ATOM_INVALID_SYMBOL; | |
162 return; | |
163 } | |
164 | |
165 DCpointer pret; | |
166 DCfloat fret; | |
167 DCdouble dret; | |
168 DCint iret; | |
169 DCbool bret; | |
170 DCshort sret; | |
171 DClong lret; | |
172 DClonglong llret; | |
173 | |
174 char* tmpstr; | |
175 size_t sz; | |
176 DCpointer ptr_persistent; | |
177 | |
178 switch(rettype) { | |
179 case DC_SIGCHAR_VOID: | |
180 dcCallVoid(vm,sym); | |
181 return; | |
182 case DC_SIGCHAR_BOOL: | |
183 bret = dcCallBool(vm,sym); | |
184 tmpstr = bret ? ATOM_TRUE : ATOM_FALSE; | |
185 *retvalue = enif_make_atom(env,tmpstr); | |
186 return; | |
187 case DC_SIGCHAR_CHAR: | |
188 iret = dcCallChar(vm,sym); | |
189 *retvalue = enif_make_int(env,(char)iret); | |
190 return; | |
191 case DC_SIGCHAR_UCHAR: | |
192 iret = dcCallChar(vm,sym); | |
193 *retvalue = enif_make_int(env,(unsigned char)iret); | |
194 return; | |
195 case DC_SIGCHAR_SHORT: | |
196 sret = dcCallShort(vm,sym); | |
197 *retvalue = enif_make_int(env,sret); | |
198 return; | |
199 case DC_SIGCHAR_USHORT: | |
200 sret = dcCallShort(vm,sym); | |
201 *retvalue = enif_make_int(env,(unsigned short)sret); | |
202 return; | |
203 case DC_SIGCHAR_INT: | |
204 iret = dcCallInt(vm,sym); | |
205 *retvalue = enif_make_int(env,iret); | |
206 return; | |
207 case DC_SIGCHAR_UINT: | |
208 iret = dcCallInt(vm,sym); | |
209 *retvalue = enif_make_int(env,(unsigned int)iret); | |
210 return; | |
211 case DC_SIGCHAR_LONG: | |
212 lret = dcCallLong(vm,sym); | |
213 *retvalue = enif_make_long(env,lret); | |
214 return; | |
215 case DC_SIGCHAR_ULONG: | |
216 lret = dcCallLong(vm,sym); | |
217 *retvalue = enif_make_long(env,(unsigned long)lret); | |
218 return; | |
219 case DC_SIGCHAR_LONGLONG: | |
220 llret = dcCallLongLong(vm,sym); | |
221 *retvalue = enif_make_int64(env,llret); | |
222 return; | |
223 case DC_SIGCHAR_ULONGLONG: | |
224 llret = dcCallLongLong(vm,sym); | |
225 *retvalue = enif_make_int64(env,(unsigned long long)llret); | |
226 return; | |
227 case DC_SIGCHAR_FLOAT: | |
228 fret = dcCallFloat(vm,sym); | |
229 *retvalue = enif_make_double(env,fret); | |
230 return; | |
231 case DC_SIGCHAR_DOUBLE: | |
232 dret = dcCallDouble(vm,sym); | |
233 *retvalue = enif_make_double(env,dret); | |
234 return; | |
235 case DC_SIGCHAR_POINTER: | |
236 pret = dcCallPointer(vm,sym); | |
237 sz = sizeof(DCpointer); | |
238 | |
239 ptr_persistent = enif_alloc_resource(g_ptrrestype,sz); | |
240 memcpy(ptr_persistent,&pret,sz); | |
241 *retvalue = enif_make_resource(env,ptr_persistent); | |
242 enif_release_resource(ptr_persistent); | |
243 return; | |
244 case DC_SIGCHAR_STRING: | |
245 pret = dcCallPointer(vm,sym); | |
246 *retvalue = enif_make_string(env,pret,ERL_NIF_LATIN1); | |
247 break; | |
248 case DC_SIGCHAR_STRUCT: | |
249 *error_atom=ATOM_NOT_IMPLEMENTED; | |
250 return; | |
251 default: | |
252 *error_atom=ATOM_INVALID_FORMAT; | |
253 return; | |
254 } | |
255 } | |
256 | |
257 | |
258 static void exec_arg(ErlNifEnv* env,void* vm,char argtype,ERL_NIF_TERM argterm,char** error_atom) { | |
259 char carg; | |
260 long int larg = -1; | |
261 int iarg = -1; | |
262 char sarg[MAX_STRING_ARG_SZ]; | |
263 double darg = -1.0; | |
264 char barg[BOOL_BUF_SZ]; | |
265 ErlNifSInt64 llarg = -1; | |
266 void** parg; | |
267 | |
268 switch(argtype) { | |
269 case DC_SIGCHAR_BOOL: | |
270 if(!enif_get_atom(env, argterm, barg, BOOL_BUF_SZ, ERL_NIF_LATIN1)) { | |
271 *error_atom = ATOM_INVALID_ARG; | |
272 return; | |
273 } | |
274 dcArgBool(vm,!strcmp(barg,ATOM_TRUE)); | |
275 break; | |
276 case DC_SIGCHAR_CHAR: | |
277 if(!enif_get_int(env, argterm, &iarg)) { | |
278 *error_atom = ATOM_INVALID_ARG; | |
279 return; | |
280 } | |
281 dcArgChar(vm,(char)iarg); | |
282 break; | |
283 case DC_SIGCHAR_UCHAR: | |
284 if(!enif_get_int(env, argterm, &iarg)) { | |
285 *error_atom = ATOM_INVALID_ARG; | |
286 return; | |
287 } | |
288 dcArgInt(vm,(unsigned char)iarg); | |
289 break; | |
290 case DC_SIGCHAR_SHORT: | |
291 if(!enif_get_int(env, argterm, &iarg)) { | |
292 *error_atom = ATOM_INVALID_ARG; | |
293 return; | |
294 } | |
295 dcArgShort(vm,(short)iarg); | |
296 break; | |
297 case DC_SIGCHAR_USHORT: | |
298 if(!enif_get_int(env, argterm, &iarg)) { | |
299 *error_atom = ATOM_INVALID_ARG; | |
300 return; | |
301 } | |
302 dcArgShort(vm,(unsigned short)iarg); | |
303 break; | |
304 case DC_SIGCHAR_INT: | |
305 if(!enif_get_int(env, argterm, &iarg)) { | |
306 *error_atom = ATOM_INVALID_ARG; | |
307 return; | |
308 } | |
309 dcArgInt(vm,iarg); | |
310 break; | |
311 case DC_SIGCHAR_UINT: | |
312 if(!enif_get_int(env, argterm, &iarg)) { | |
313 *error_atom = ATOM_INVALID_ARG; | |
314 return; | |
315 } | |
316 dcArgInt(vm,(unsigned int)iarg); | |
317 break; | |
318 case DC_SIGCHAR_LONG: | |
319 if(!enif_get_long(env, argterm, &larg)) { | |
320 *error_atom = ATOM_INVALID_ARG; | |
321 return; | |
322 } | |
323 dcArgLong(vm,larg); | |
324 break; | |
325 case DC_SIGCHAR_ULONG: | |
326 if(!enif_get_long(env, argterm, &larg)) { | |
327 *error_atom = ATOM_INVALID_ARG; | |
328 return; | |
329 } | |
330 dcArgLong(vm,(unsigned long)larg); | |
331 break; | |
332 case DC_SIGCHAR_LONGLONG: | |
333 if(!enif_get_int64(env, argterm, &llarg)) { | |
334 *error_atom = ATOM_INVALID_ARG; | |
335 return; | |
336 } | |
337 dcArgLongLong(vm,llarg); | |
338 break; | |
339 case DC_SIGCHAR_ULONGLONG: | |
340 if(!enif_get_int64(env, argterm, &llarg)) { | |
341 *error_atom = ATOM_INVALID_ARG; | |
342 return; | |
343 } | |
344 dcArgLongLong(vm,(unsigned long long)llarg); | |
345 break; | |
346 case DC_SIGCHAR_FLOAT: | |
347 if(!enif_get_double(env, argterm, &darg)) { | |
348 *error_atom = ATOM_INVALID_ARG; | |
349 return; | |
350 } | |
351 dcArgFloat(vm,(float)darg); | |
352 break; | |
353 case DC_SIGCHAR_DOUBLE: | |
354 if(!enif_get_double(env, argterm, &darg)) { | |
355 *error_atom = ATOM_INVALID_ARG; | |
356 return; | |
357 } | |
358 dcArgDouble(vm,darg); | |
359 break; | |
360 case DC_SIGCHAR_POINTER: | |
361 if(!enif_get_resource(env, argterm, g_ptrrestype, (void**)&parg)) { | |
362 *error_atom = ATOM_INVALID_ARG; | |
363 return; | |
364 } | |
365 dcArgPointer(vm,*parg); | |
366 break; | |
367 case DC_SIGCHAR_STRING: | |
368 if(!enif_get_string(env, argterm, sarg, MAX_STRING_ARG_SZ, ERL_NIF_LATIN1)) { | |
369 *error_atom = ATOM_INVALID_ARG; | |
370 return; | |
371 } | |
372 dcArgPointer(vm,sarg); | |
373 break; | |
374 case DC_SIGCHAR_STRUCT: | |
375 *error_atom = ATOM_NOT_IMPLEMENTED; | |
376 return; | |
377 default: | |
378 *error_atom = ATOM_INVALID_FORMAT; | |
379 return; | |
380 } | |
381 } | |
382 | |
383 #define GET_VM void** vmptr; \ | |
384 if(!enif_get_resource(env, argv[0], g_vmrestype, (void**)&vmptr)) RETURN_ERROR(ATOM_INVALID_VM); \ | |
385 if(!*vmptr) RETURN_ERROR(ATOM_INVALID_VM); | |
386 | |
387 #define GET_SYM void** symptr; \ | |
388 if(!enif_get_resource(env, argv[1], g_ptrrestype, (void**)&symptr)) RETURN_ERROR(ATOM_INVALID_ARG); | |
389 | |
390 #define EXEC_CALL(typechar) ERL_NIF_TERM retvalue; \ | |
391 char* error_atom = NULL; \ | |
392 exec_call(env,*vmptr,*symptr,typechar,&retvalue,&error_atom); | |
393 | |
394 #define MAKE_CALL_RETURN if(error_atom) RETURN_ERROR(error_atom); \ | |
395 return enif_make_tuple2(env, \ | |
396 enif_make_atom(env,ATOM_OK), \ | |
397 retvalue \ | |
398 ); | |
399 | |
400 #define EXEC_ARG(typechar) char* error_atom = NULL; \ | |
401 exec_arg(env,*vmptr,typechar,argv[1],&error_atom); | |
402 | |
403 #define MAKE_ARG_RETURN if(error_atom) RETURN_ERROR(error_atom); \ | |
404 return enif_make_atom(env,ATOM_OK); | |
405 | |
406 | |
407 static ERL_NIF_TERM arg_double(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
408 GET_VM; | |
409 EXEC_ARG(DC_SIGCHAR_DOUBLE); | |
410 MAKE_ARG_RETURN; | |
411 } | |
412 | |
413 static ERL_NIF_TERM call_double(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
414 GET_VM; | |
415 GET_SYM; | |
416 EXEC_CALL(DC_SIGCHAR_DOUBLE); | |
417 MAKE_CALL_RETURN; | |
418 } | |
419 | |
420 static ERL_NIF_TERM arg_float(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
421 GET_VM; | |
422 EXEC_ARG(DC_SIGCHAR_FLOAT); | |
423 MAKE_ARG_RETURN; | |
424 } | |
425 | |
426 static ERL_NIF_TERM call_float(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
427 GET_VM; | |
428 GET_SYM; | |
429 EXEC_CALL(DC_SIGCHAR_FLOAT); | |
430 MAKE_CALL_RETURN; | |
431 } | |
432 | |
433 static ERL_NIF_TERM arg_int(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
434 GET_VM; | |
435 EXEC_ARG(DC_SIGCHAR_INT); | |
436 MAKE_ARG_RETURN; | |
437 } | |
438 | |
439 static ERL_NIF_TERM call_int(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
440 GET_VM; | |
441 GET_SYM; | |
442 EXEC_CALL(DC_SIGCHAR_INT); | |
443 MAKE_CALL_RETURN; | |
444 } | |
445 | |
446 static ERL_NIF_TERM arg_char(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
447 GET_VM; | |
448 EXEC_ARG(DC_SIGCHAR_CHAR); | |
449 MAKE_ARG_RETURN; | |
450 } | |
451 | |
452 static ERL_NIF_TERM call_char(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
453 GET_VM; | |
454 GET_SYM; | |
455 EXEC_CALL(DC_SIGCHAR_CHAR); | |
456 MAKE_CALL_RETURN; | |
457 } | |
458 | |
459 static ERL_NIF_TERM arg_bool(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
460 GET_VM; | |
461 EXEC_ARG(DC_SIGCHAR_BOOL); | |
462 MAKE_ARG_RETURN; | |
463 } | |
464 | |
465 static ERL_NIF_TERM call_bool(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
466 GET_VM; | |
467 GET_SYM; | |
468 EXEC_CALL(DC_SIGCHAR_BOOL); | |
469 MAKE_CALL_RETURN; | |
470 } | |
471 | |
472 static ERL_NIF_TERM arg_short(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
473 GET_VM; | |
474 EXEC_ARG(DC_SIGCHAR_SHORT); | |
475 MAKE_ARG_RETURN; | |
476 } | |
477 | |
478 static ERL_NIF_TERM call_short(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
479 GET_VM; | |
480 GET_SYM; | |
481 EXEC_CALL(DC_SIGCHAR_SHORT); | |
482 MAKE_CALL_RETURN; | |
483 } | |
484 | |
485 static ERL_NIF_TERM arg_long(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
486 GET_VM; | |
487 EXEC_ARG(DC_SIGCHAR_LONG); | |
488 MAKE_ARG_RETURN; | |
489 } | |
490 | |
491 static ERL_NIF_TERM call_long(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
492 GET_VM; | |
493 GET_SYM; | |
494 EXEC_CALL(DC_SIGCHAR_LONG); | |
495 MAKE_CALL_RETURN; | |
496 } | |
497 | |
498 static ERL_NIF_TERM arg_longlong(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
499 GET_VM; | |
500 EXEC_ARG(DC_SIGCHAR_LONGLONG); | |
501 MAKE_ARG_RETURN; | |
502 } | |
503 | |
504 static ERL_NIF_TERM call_longlong(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
505 GET_VM; | |
506 GET_SYM; | |
507 EXEC_CALL(DC_SIGCHAR_LONGLONG); | |
508 MAKE_CALL_RETURN; | |
509 } | |
510 | |
511 static ERL_NIF_TERM arg_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
512 GET_VM; | |
513 EXEC_ARG(DC_SIGCHAR_POINTER); | |
514 MAKE_ARG_RETURN; | |
515 } | |
516 | |
517 static ERL_NIF_TERM call_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
518 GET_VM; | |
519 GET_SYM; | |
520 EXEC_CALL(DC_SIGCHAR_POINTER); | |
521 MAKE_CALL_RETURN; | |
522 } | |
523 | |
524 static ERL_NIF_TERM call_void(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
525 GET_VM; | |
526 GET_SYM; | |
527 EXEC_CALL(DC_SIGCHAR_VOID); | |
528 | |
529 if(error_atom) RETURN_ERROR(error_atom); | |
530 return enif_make_atom(env,ATOM_OK); | |
531 } | |
532 | |
533 static ERL_NIF_TERM arg_string(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
534 GET_VM; | |
535 EXEC_ARG(DC_SIGCHAR_STRING); | |
536 MAKE_ARG_RETURN; | |
537 } | |
538 | |
539 static ERL_NIF_TERM call_string(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
540 GET_VM; | |
541 GET_SYM; | |
542 EXEC_CALL(DC_SIGCHAR_STRING); | |
543 MAKE_CALL_RETURN; | |
544 } | |
545 | |
546 static ERL_NIF_TERM mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
547 GET_VM; | |
548 | |
549 int mode = -1; | |
550 if(!enif_get_int(env, argv[1], &mode)) RETURN_ERROR(ATOM_INVALID_ARG) | |
551 | |
552 dcMode(*vmptr,mode); | |
553 return enif_make_atom(env,ATOM_OK); | |
554 } | |
555 | |
556 static ERL_NIF_TERM get_error(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
557 GET_VM; | |
558 | |
559 DCint ret = dcGetError(*vmptr); | |
560 | |
561 return enif_make_tuple2(env, | |
562 enif_make_atom(env,ATOM_OK), | |
563 enif_make_int(env,ret) | |
564 ); | |
565 } | |
566 | |
567 static ERL_NIF_TERM reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
568 GET_VM; | |
569 | |
570 dcReset(*vmptr); | |
571 return enif_make_atom(env,ATOM_OK); | |
572 } | |
573 | |
574 static void process_formatted_args(ErlNifEnv* env,void* vm,char** format,ERL_NIF_TERM arglist,char** error_atom) { | |
575 | |
576 ERL_NIF_TERM remaining = arglist; | |
577 | |
578 char sigchar; | |
579 char* onechar = *format; | |
580 while((sigchar=*onechar)) { | |
581 if(sigchar==DC_SIGCHAR_ENDARG) break; | |
582 | |
583 // If the format has more items than the arg list, | |
584 // fail and call it a bad format. | |
585 ERL_NIF_TERM first, rest; | |
586 if(!enif_get_list_cell(env, remaining, &first, &rest)) { | |
587 *error_atom = ATOM_INVALID_FORMAT; | |
588 return; | |
589 } | |
590 | |
591 exec_arg(env,vm,sigchar,first,error_atom); | |
592 | |
593 remaining = rest; | |
594 onechar++; | |
595 } | |
596 | |
597 // There are more args, but the format was exhausted | |
598 if(!enif_is_empty_list(env,remaining)) { | |
599 *error_atom = ATOM_INVALID_FORMAT; | |
600 return; | |
601 } | |
602 | |
603 *format = onechar; | |
604 } | |
605 | |
606 static ERL_NIF_TERM argf(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
607 GET_VM; | |
608 MAYBE_RET_BAD_STRING_ARG(format,1,MAX_FORMAT_STRING_SZ,ATOM_INVALID_FORMAT); | |
609 | |
610 char* formatretyped = format; | |
611 char* error_atom = NULL; | |
612 process_formatted_args(env,*vmptr,&formatretyped, argv[2], &error_atom); | |
613 | |
614 if(error_atom) { | |
615 RETURN_ERROR(error_atom); | |
616 } else return enif_make_atom(env,ATOM_OK); | |
617 } | |
618 | |
619 static ERL_NIF_TERM callf(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { | |
620 GET_VM; | |
621 | |
622 void** symptr; | |
623 if(!enif_get_resource(env, argv[1], g_ptrrestype, (void**)&symptr)) RETURN_ERROR(ATOM_INVALID_ARG) | |
624 if(!*symptr) RETURN_ERROR(ATOM_INVALID_SYMBOL) | |
625 | |
626 MAYBE_RET_BAD_STRING_ARG(format,2,MAX_FORMAT_STRING_SZ,ATOM_INVALID_FORMAT); | |
627 | |
628 char* formatretyped = format; | |
629 char* error_atom = NULL; | |
630 process_formatted_args(env,*vmptr,&formatretyped, argv[3], &error_atom); | |
631 | |
632 if(error_atom) { | |
633 RETURN_ERROR(error_atom); | |
634 } | |
635 | |
636 // Get return type char, skip ) | |
637 char rettypechar = *(formatretyped+1); | |
638 | |
639 ERL_NIF_TERM retval; | |
640 | |
641 exec_call(env,*vmptr,*symptr,rettypechar,&retval,&error_atom); | |
642 | |
643 if(error_atom) { | |
644 RETURN_ERROR(error_atom); | |
645 } | |
646 | |
647 if(rettypechar == DC_SIGCHAR_VOID) { | |
648 return enif_make_atom(env,ATOM_OK); | |
649 } | |
650 | |
651 return enif_make_tuple2(env, | |
652 enif_make_atom(env,ATOM_OK), | |
653 retval | |
654 ); | |
655 } | |
656 | |
657 static ErlNifFunc nif_funcs[] = { | |
658 {"new_call_vm", 1, new_call_vm}, | |
659 {"mode", 2, mode}, | |
660 {"get_error", 1, get_error}, | |
661 {"reset", 1, reset}, | |
662 {"load_library", 1, load_library}, | |
663 {"find_symbol", 2, find_symbol}, | |
664 {"arg_double", 2, arg_double}, | |
665 {"call_double", 2, call_double}, | |
666 {"arg_float", 2, arg_float}, | |
667 {"call_float", 2, call_float}, | |
668 {"arg_int", 2, arg_int}, | |
669 {"call_int", 2, call_int}, | |
670 {"arg_char", 2, arg_char}, | |
671 {"call_char", 2, call_char}, | |
672 {"arg_bool", 2, arg_bool}, | |
673 {"call_bool", 2, call_bool}, | |
674 {"arg_short", 2, arg_short}, | |
675 {"call_short", 2, call_short}, | |
676 {"arg_long", 2, arg_long}, | |
677 {"call_long", 2, call_long}, | |
678 {"arg_longlong", 2, arg_longlong}, | |
679 {"call_longlong", 2, call_longlong}, | |
680 {"arg_ptr", 2, arg_ptr}, | |
681 {"call_ptr", 2, call_ptr}, | |
682 {"call_void", 2, call_void}, | |
683 {"arg_string", 2, arg_string}, | |
684 {"call_string", 2, call_string}, | |
685 | |
686 {"argf", 3, argf}, | |
687 {"callf", 4, callf} | |
688 }; | |
689 | |
690 ERL_NIF_INIT(dyncall,nif_funcs,&nifload,NULL,NULL,NULL) |