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)