Mercurial > pub > dyncall > bindings
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/erlang/erldc/c_src/dyncallnif.c Thu Mar 19 22:26:28 2015 +0100 @@ -0,0 +1,690 @@ +/* + Copyright (c) 2014 Erik Mackdanz <erikmack@gmail.com> + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +#include "erl_nif.h" +#include "dyncall/dyncall.h" +#include "dyncall/dyncall_signature.h" + +#include <string.h> +#include <stdio.h> + +/************ Begin NIF initialization *******/ + +#define MAX_LIBPATH_SZ 128 +#define MAX_SYMBOL_NAME_SZ 32 +#define MAX_FORMAT_STRING_SZ 100 +#define MAX_STRING_ARG_SZ 1024 + +ErlNifResourceType *g_ptrrestype, *g_vmrestype; + +static void noop_dtor(ErlNifEnv* env, void* obj) { + // When erlang gc's a ptr, no-op since we can't know how to free it. + // Likewise with symbols, etc. +} +static void vm_dtor(ErlNifEnv* env, void* obj) { + void** ptr = (void**)obj; + dcFree(*ptr); +} + +static int nifload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + + // Allows us to have a native pointer (to vm, lib, symbol, or user-defined) and + // pass a safe opaque handle into erlang + g_ptrrestype = enif_open_resource_type(env,"dyncall","pointer", + noop_dtor,ERL_NIF_RT_CREATE, + NULL); + + // Works like g_ptrrestype, but requires a dtor that calls dcFree + g_vmrestype = enif_open_resource_type(env,"dyncall","vmpointer", + vm_dtor,ERL_NIF_RT_CREATE, + NULL); + + return 0; +} + +/************ End NIF initialization *******/ + +#define ATOM_OK "ok" +#define ATOM_ERROR "error" + +#define ATOM_LIB_NOT_FOUND "lib_not_found" +#define ATOM_SYMBOL_NOT_FOUND "symbol_not_found" +#define ATOM_BADSZ "bad_vm_size" +#define ATOM_INVALID_VM "invalid_vm" +#define ATOM_INVALID_LIB "invalid_lib" +#define ATOM_INVALID_SYMBOL "invalid_symbol" +#define ATOM_INVALID_FORMAT "invalid_format" +#define ATOM_INVALID_ARG "invalid_arg" +#define ATOM_NOT_IMPLEMENTED "not_implemented" + +static ERL_NIF_TERM new_call_vm(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + + long vmsz = 0; + if(!enif_get_long(env, argv[0], &vmsz)) { + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_ERROR), + enif_make_atom(env,ATOM_BADSZ) + ); + } + + DCCallVM* vm = dcNewCallVM( vmsz ); + + size_t sz = sizeof(DCCallVM*); + DCpointer ptr_persistent_vm = enif_alloc_resource(g_vmrestype,sz); + memcpy(ptr_persistent_vm,&vm,sz); + ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_vm); + enif_release_resource(ptr_persistent_vm); + + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_OK), + retterm + ); +} + +#define MAYBE_RET_BAD_STRING_ARG(indexvar,argi,limit,retatom) \ + char indexvar[limit]; \ + indexvar[limit-1] = 0; \ + if(enif_get_string(env, argv[argi], indexvar, limit, ERL_NIF_LATIN1) <= 0) { \ + return enif_make_tuple2(env, \ + enif_make_atom(env,ATOM_ERROR), \ + enif_make_atom(env,retatom) \ + ); \ + } + +#define RETURN_ERROR(code) return enif_make_tuple2(env, \ + enif_make_atom(env,ATOM_ERROR), \ + enif_make_atom(env,code) \ + ); + +static ERL_NIF_TERM load_library(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + MAYBE_RET_BAD_STRING_ARG(path,0,MAX_LIBPATH_SZ,ATOM_INVALID_LIB) + + void* libptr = enif_dlopen(path, NULL, NULL); + + // Error if dlLoadLibrary returned NULL + if(!libptr) RETURN_ERROR(ATOM_LIB_NOT_FOUND) + + size_t sz = sizeof(void*); + DCpointer ptr_persistent_lib = enif_alloc_resource(g_ptrrestype,sz); + memcpy(ptr_persistent_lib,&libptr,sz); + ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_lib); + enif_release_resource(ptr_persistent_lib); + + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_OK), + retterm + ); +} + +static ERL_NIF_TERM find_symbol(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + MAYBE_RET_BAD_STRING_ARG(path,1,MAX_SYMBOL_NAME_SZ,ATOM_INVALID_SYMBOL) + + void** libptr; + if(!enif_get_resource(env, argv[0], g_ptrrestype, (void**)&libptr)) RETURN_ERROR(ATOM_INVALID_LIB) + + void* symptr = enif_dlsym(*libptr,path,NULL,NULL); + + size_t sz = sizeof(void*); + DCpointer ptr_persistent_symbol = enif_alloc_resource(g_ptrrestype,sz); + memcpy(ptr_persistent_symbol,&symptr,sz); + ERL_NIF_TERM retterm = enif_make_resource(env,ptr_persistent_symbol); + enif_release_resource(ptr_persistent_symbol); + + // Error if enif_dlsym returned NULL + if(!symptr) RETURN_ERROR(ATOM_SYMBOL_NOT_FOUND) + + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_OK), + retterm + ); +} + +#define BOOL_BUF_SZ 6 +#define ATOM_TRUE "true" +#define ATOM_FALSE "false" + +static void exec_call(ErlNifEnv* env, void* vm, void* sym, char rettype,ERL_NIF_TERM *retvalue, char** error_atom) { + if(!sym) { + *error_atom = ATOM_INVALID_SYMBOL; + return; + } + + DCpointer pret; + DCfloat fret; + DCdouble dret; + DCint iret; + DCbool bret; + DCshort sret; + DClong lret; + DClonglong llret; + + char* tmpstr; + size_t sz; + DCpointer ptr_persistent; + + switch(rettype) { + case DC_SIGCHAR_VOID: + dcCallVoid(vm,sym); + return; + case DC_SIGCHAR_BOOL: + bret = dcCallBool(vm,sym); + tmpstr = bret ? ATOM_TRUE : ATOM_FALSE; + *retvalue = enif_make_atom(env,tmpstr); + return; + case DC_SIGCHAR_CHAR: + iret = dcCallChar(vm,sym); + *retvalue = enif_make_int(env,(char)iret); + return; + case DC_SIGCHAR_UCHAR: + iret = dcCallChar(vm,sym); + *retvalue = enif_make_int(env,(unsigned char)iret); + return; + case DC_SIGCHAR_SHORT: + sret = dcCallShort(vm,sym); + *retvalue = enif_make_int(env,sret); + return; + case DC_SIGCHAR_USHORT: + sret = dcCallShort(vm,sym); + *retvalue = enif_make_int(env,(unsigned short)sret); + return; + case DC_SIGCHAR_INT: + iret = dcCallInt(vm,sym); + *retvalue = enif_make_int(env,iret); + return; + case DC_SIGCHAR_UINT: + iret = dcCallInt(vm,sym); + *retvalue = enif_make_int(env,(unsigned int)iret); + return; + case DC_SIGCHAR_LONG: + lret = dcCallLong(vm,sym); + *retvalue = enif_make_long(env,lret); + return; + case DC_SIGCHAR_ULONG: + lret = dcCallLong(vm,sym); + *retvalue = enif_make_long(env,(unsigned long)lret); + return; + case DC_SIGCHAR_LONGLONG: + llret = dcCallLongLong(vm,sym); + *retvalue = enif_make_int64(env,llret); + return; + case DC_SIGCHAR_ULONGLONG: + llret = dcCallLongLong(vm,sym); + *retvalue = enif_make_int64(env,(unsigned long long)llret); + return; + case DC_SIGCHAR_FLOAT: + fret = dcCallFloat(vm,sym); + *retvalue = enif_make_double(env,fret); + return; + case DC_SIGCHAR_DOUBLE: + dret = dcCallDouble(vm,sym); + *retvalue = enif_make_double(env,dret); + return; + case DC_SIGCHAR_POINTER: + pret = dcCallPointer(vm,sym); + sz = sizeof(DCpointer); + + ptr_persistent = enif_alloc_resource(g_ptrrestype,sz); + memcpy(ptr_persistent,&pret,sz); + *retvalue = enif_make_resource(env,ptr_persistent); + enif_release_resource(ptr_persistent); + return; + case DC_SIGCHAR_STRING: + pret = dcCallPointer(vm,sym); + *retvalue = enif_make_string(env,pret,ERL_NIF_LATIN1); + break; + case DC_SIGCHAR_STRUCT: + *error_atom=ATOM_NOT_IMPLEMENTED; + return; + default: + *error_atom=ATOM_INVALID_FORMAT; + return; + } +} + + +static void exec_arg(ErlNifEnv* env,void* vm,char argtype,ERL_NIF_TERM argterm,char** error_atom) { + char carg; + long int larg = -1; + int iarg = -1; + char sarg[MAX_STRING_ARG_SZ]; + double darg = -1.0; + char barg[BOOL_BUF_SZ]; + ErlNifSInt64 llarg = -1; + void** parg; + + switch(argtype) { + case DC_SIGCHAR_BOOL: + if(!enif_get_atom(env, argterm, barg, BOOL_BUF_SZ, ERL_NIF_LATIN1)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgBool(vm,!strcmp(barg,ATOM_TRUE)); + break; + case DC_SIGCHAR_CHAR: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgChar(vm,(char)iarg); + break; + case DC_SIGCHAR_UCHAR: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgInt(vm,(unsigned char)iarg); + break; + case DC_SIGCHAR_SHORT: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgShort(vm,(short)iarg); + break; + case DC_SIGCHAR_USHORT: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgShort(vm,(unsigned short)iarg); + break; + case DC_SIGCHAR_INT: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgInt(vm,iarg); + break; + case DC_SIGCHAR_UINT: + if(!enif_get_int(env, argterm, &iarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgInt(vm,(unsigned int)iarg); + break; + case DC_SIGCHAR_LONG: + if(!enif_get_long(env, argterm, &larg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgLong(vm,larg); + break; + case DC_SIGCHAR_ULONG: + if(!enif_get_long(env, argterm, &larg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgLong(vm,(unsigned long)larg); + break; + case DC_SIGCHAR_LONGLONG: + if(!enif_get_int64(env, argterm, &llarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgLongLong(vm,llarg); + break; + case DC_SIGCHAR_ULONGLONG: + if(!enif_get_int64(env, argterm, &llarg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgLongLong(vm,(unsigned long long)llarg); + break; + case DC_SIGCHAR_FLOAT: + if(!enif_get_double(env, argterm, &darg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgFloat(vm,(float)darg); + break; + case DC_SIGCHAR_DOUBLE: + if(!enif_get_double(env, argterm, &darg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgDouble(vm,darg); + break; + case DC_SIGCHAR_POINTER: + if(!enif_get_resource(env, argterm, g_ptrrestype, (void**)&parg)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgPointer(vm,*parg); + break; + case DC_SIGCHAR_STRING: + if(!enif_get_string(env, argterm, sarg, MAX_STRING_ARG_SZ, ERL_NIF_LATIN1)) { + *error_atom = ATOM_INVALID_ARG; + return; + } + dcArgPointer(vm,sarg); + break; + case DC_SIGCHAR_STRUCT: + *error_atom = ATOM_NOT_IMPLEMENTED; + return; + default: + *error_atom = ATOM_INVALID_FORMAT; + return; + } +} + +#define GET_VM void** vmptr; \ + if(!enif_get_resource(env, argv[0], g_vmrestype, (void**)&vmptr)) RETURN_ERROR(ATOM_INVALID_VM); \ + if(!*vmptr) RETURN_ERROR(ATOM_INVALID_VM); + +#define GET_SYM void** symptr; \ + if(!enif_get_resource(env, argv[1], g_ptrrestype, (void**)&symptr)) RETURN_ERROR(ATOM_INVALID_ARG); + +#define EXEC_CALL(typechar) ERL_NIF_TERM retvalue; \ + char* error_atom = NULL; \ + exec_call(env,*vmptr,*symptr,typechar,&retvalue,&error_atom); + +#define MAKE_CALL_RETURN if(error_atom) RETURN_ERROR(error_atom); \ + return enif_make_tuple2(env, \ + enif_make_atom(env,ATOM_OK), \ + retvalue \ + ); + +#define EXEC_ARG(typechar) char* error_atom = NULL; \ + exec_arg(env,*vmptr,typechar,argv[1],&error_atom); + +#define MAKE_ARG_RETURN if(error_atom) RETURN_ERROR(error_atom); \ + return enif_make_atom(env,ATOM_OK); + + +static ERL_NIF_TERM arg_double(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_DOUBLE); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_double(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_DOUBLE); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_float(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_FLOAT); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_float(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_FLOAT); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_int(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_INT); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_int(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_INT); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_char(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_CHAR); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_char(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_CHAR); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_bool(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_BOOL); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_bool(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_BOOL); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_short(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_SHORT); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_short(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_SHORT); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_long(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_LONG); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_long(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_LONG); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_longlong(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_LONGLONG); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_longlong(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_LONGLONG); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM arg_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_POINTER); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_ptr(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_POINTER); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM call_void(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_VOID); + + if(error_atom) RETURN_ERROR(error_atom); + return enif_make_atom(env,ATOM_OK); +} + +static ERL_NIF_TERM arg_string(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + EXEC_ARG(DC_SIGCHAR_STRING); + MAKE_ARG_RETURN; +} + +static ERL_NIF_TERM call_string(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + GET_SYM; + EXEC_CALL(DC_SIGCHAR_STRING); + MAKE_CALL_RETURN; +} + +static ERL_NIF_TERM mode(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + + int mode = -1; + if(!enif_get_int(env, argv[1], &mode)) RETURN_ERROR(ATOM_INVALID_ARG) + + dcMode(*vmptr,mode); + return enif_make_atom(env,ATOM_OK); +} + +static ERL_NIF_TERM get_error(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + + DCint ret = dcGetError(*vmptr); + + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_OK), + enif_make_int(env,ret) + ); +} + +static ERL_NIF_TERM reset(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + + dcReset(*vmptr); + return enif_make_atom(env,ATOM_OK); +} + +static void process_formatted_args(ErlNifEnv* env,void* vm,char** format,ERL_NIF_TERM arglist,char** error_atom) { + + ERL_NIF_TERM remaining = arglist; + + char sigchar; + char* onechar = *format; + while((sigchar=*onechar)) { + if(sigchar==DC_SIGCHAR_ENDARG) break; + + // If the format has more items than the arg list, + // fail and call it a bad format. + ERL_NIF_TERM first, rest; + if(!enif_get_list_cell(env, remaining, &first, &rest)) { + *error_atom = ATOM_INVALID_FORMAT; + return; + } + + exec_arg(env,vm,sigchar,first,error_atom); + + remaining = rest; + onechar++; + } + + // There are more args, but the format was exhausted + if(!enif_is_empty_list(env,remaining)) { + *error_atom = ATOM_INVALID_FORMAT; + return; + } + + *format = onechar; +} + +static ERL_NIF_TERM argf(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + MAYBE_RET_BAD_STRING_ARG(format,1,MAX_FORMAT_STRING_SZ,ATOM_INVALID_FORMAT); + + char* formatretyped = format; + char* error_atom = NULL; + process_formatted_args(env,*vmptr,&formatretyped, argv[2], &error_atom); + + if(error_atom) { + RETURN_ERROR(error_atom); + } else return enif_make_atom(env,ATOM_OK); +} + +static ERL_NIF_TERM callf(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + GET_VM; + + void** symptr; + if(!enif_get_resource(env, argv[1], g_ptrrestype, (void**)&symptr)) RETURN_ERROR(ATOM_INVALID_ARG) + if(!*symptr) RETURN_ERROR(ATOM_INVALID_SYMBOL) + + MAYBE_RET_BAD_STRING_ARG(format,2,MAX_FORMAT_STRING_SZ,ATOM_INVALID_FORMAT); + + char* formatretyped = format; + char* error_atom = NULL; + process_formatted_args(env,*vmptr,&formatretyped, argv[3], &error_atom); + + if(error_atom) { + RETURN_ERROR(error_atom); + } + + // Get return type char, skip ) + char rettypechar = *(formatretyped+1); + + ERL_NIF_TERM retval; + + exec_call(env,*vmptr,*symptr,rettypechar,&retval,&error_atom); + + if(error_atom) { + RETURN_ERROR(error_atom); + } + + if(rettypechar == DC_SIGCHAR_VOID) { + return enif_make_atom(env,ATOM_OK); + } + + return enif_make_tuple2(env, + enif_make_atom(env,ATOM_OK), + retval + ); +} + +static ErlNifFunc nif_funcs[] = { + {"new_call_vm", 1, new_call_vm}, + {"mode", 2, mode}, + {"get_error", 1, get_error}, + {"reset", 1, reset}, + {"load_library", 1, load_library}, + {"find_symbol", 2, find_symbol}, + {"arg_double", 2, arg_double}, + {"call_double", 2, call_double}, + {"arg_float", 2, arg_float}, + {"call_float", 2, call_float}, + {"arg_int", 2, arg_int}, + {"call_int", 2, call_int}, + {"arg_char", 2, arg_char}, + {"call_char", 2, call_char}, + {"arg_bool", 2, arg_bool}, + {"call_bool", 2, call_bool}, + {"arg_short", 2, arg_short}, + {"call_short", 2, call_short}, + {"arg_long", 2, arg_long}, + {"call_long", 2, call_long}, + {"arg_longlong", 2, arg_longlong}, + {"call_longlong", 2, call_longlong}, + {"arg_ptr", 2, arg_ptr}, + {"call_ptr", 2, call_ptr}, + {"call_void", 2, call_void}, + {"arg_string", 2, arg_string}, + {"call_string", 2, call_string}, + + {"argf", 3, argf}, + {"callf", 4, callf} +}; + +ERL_NIF_INIT(dyncall,nif_funcs,&nifload,NULL,NULL,NULL)