0
|
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)
|