Mercurial > pub > dyncall > bindings
diff R/rdc/src/api.c @ 0:0cfcc391201f
initial from svn dyncall-1745
author | Daniel Adler |
---|---|
date | Thu, 19 Mar 2015 22:26:28 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/R/rdc/src/api.c Thu Mar 19 22:26:28 2015 +0100 @@ -0,0 +1,505 @@ +#include <R.h> +#define USE_RINTERNALS +#include <Rinternals.h> +#include <R_ext/Rdynload.h> +#include "dynload.h" +#include "dyncall.h" +#include "dyncall_signature.h" + + +/* rdcLoad */ + +SEXP rdcLoad(SEXP sLibPath) +{ + void* libHandle; + const char* libPath; + SEXP r; + libPath = CHAR(STRING_ELT(sLibPath,0)); + + libHandle = dlLoadLibrary(libPath); + + if (!libHandle) { + error("rdcLoad failed on path %s", libPath ); + } + + r = R_NilValue; + + PROTECT( r = R_MakeExternalPtr(libHandle, R_NilValue, R_NilValue) ); + UNPROTECT(1); + + return r; +} + +/* rdcFree */ + +SEXP rdcFree(SEXP sLibHandle) +{ + void* libHandle; + + libHandle = R_ExternalPtrAddr(sLibHandle); + dlFreeLibrary( libHandle ); + + R_SetExternalPtrAddr(sLibHandle, 0); + return R_NilValue; +} + +/* rdcFind */ + +SEXP rdcFind(SEXP sLibHandle, SEXP sSymbol) +{ + void* libHandle; + const char* symbol; + void* addr; + SEXP r; + libHandle = R_ExternalPtrAddr(sLibHandle); + symbol = CHAR(STRING_ELT(sSymbol,0) ); + addr = dlFindSymbol( libHandle, symbol ); + + r = R_NilValue; + + PROTECT( r = R_MakeExternalPtr(addr, R_NilValue, R_NilValue) ); + UNPROTECT(1); + + return r; +} + +SEXP r_dcCall(SEXP sCallVM, SEXP sFuncPtr, SEXP sSignature, SEXP sArgs) +{ + DCCallVM* pvm; + void* funcPtr; + const char* signature; + const char* ptr; + int i,l,protect_count; + SEXP r; + + pvm = R_ExternalPtrAddr(sCallVM); + if (!pvm) error("callvm is null"); + + funcPtr = R_ExternalPtrAddr(sFuncPtr); + if (!funcPtr) error("funcptr is null"); + + signature = CHAR(STRING_ELT(sSignature,0) ); + if (!signature) error("signature is null"); + + dcReset(pvm); + ptr = signature; + + l = LENGTH(sArgs); + i = 0; + protect_count = 0; + for(;;) { + char ch = *ptr++; + SEXP arg; + + if (ch == '\0') error("invalid signature - no return type specified"); + + if (ch == ')') break; + + if (i >= l) error("not enough arguments for given signature (arg length = %d %d %c)", l,i,ch ); + + arg = VECTOR_ELT(sArgs,i); + switch(ch) { + case DC_SIGCHAR_BOOL: + { + DCbool value; + if ( isLogical(arg) ) + { + value = ( LOGICAL(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE; + } + else + { + value = LOGICAL( coerceVector(arg, LGLSXP) )[0] ? DC_FALSE : DC_TRUE; + } + dcArgBool(pvm, value ); + break; + } + case DC_SIGCHAR_INT: + { + int value; + if ( isInteger(arg) ) + { + value = INTEGER(arg)[0]; + } + else + { + value = INTEGER( coerceVector(arg, INTSXP) )[0]; + } + dcArgInt(pvm, value); + break; + } + case DC_SIGCHAR_FLOAT: + { + dcArgFloat( pvm, (float) REAL( coerceVector(arg, REALSXP) )[0] ); + break; + } + case DC_SIGCHAR_DOUBLE: + { + double value; + if ( isReal(arg) ) + { + value = REAL(arg)[0]; + } + else + { + value = REAL( coerceVector(arg,REALSXP) )[0]; + } + dcArgDouble( pvm, value ); + break; + } + /* + case DC_SIGCHAR_LONG: + { + PROTECT(arg = coerceVector(arg, REALSXP) ); + dcArgLong( pvm, (DClong) ( REAL(arg)[0] ) ); + UNPROTECT(1); + break; + } + */ + case DC_SIGCHAR_STRING: + { + DCpointer ptr; + if (arg == R_NilValue) ptr = (DCpointer) 0; + else if (isString(arg)) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); + else { + if (protect_count) UNPROTECT(protect_count); + error("invalid value for C string argument"); break; + } + } + case DC_SIGCHAR_POINTER: + { + DCpointer ptr; + if ( arg == R_NilValue ) ptr = (DCpointer) 0; + else if (isString(arg) ) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); + else if (isReal(arg) ) ptr = (DCpointer) REAL(arg); + else if (isInteger(arg) ) ptr = (DCpointer) INTEGER(arg); + else if (isLogical(arg) ) ptr = (DCpointer) LOGICAL(arg); + else if (TYPEOF(arg) == EXTPTRSXP) ptr = R_ExternalPtrAddr(arg); + else { + if (protect_count) UNPROTECT(protect_count); + error("invalid signature"); break; + } + dcArgPointer(pvm, ptr); + break; + } + } + ++i; + } + + if ( i != l ) + { + if (protect_count) + UNPROTECT(protect_count); + error ("signature claims to have %d arguments while %d arguments are given", i, l); + } + + switch(*ptr) { + case DC_SIGCHAR_BOOL: + PROTECT( r = allocVector(LGLSXP, 1) ); protect_count++; + LOGICAL(r)[0] = ( dcCallBool(pvm, funcPtr) == DC_FALSE ) ? FALSE : TRUE; + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_CHAR: + PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; + INTEGER(r)[0] = dcCallChar(pvm, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_SHORT: + PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; + INTEGER(r)[0] = dcCallShort(pvm, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_LONG: + PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; + INTEGER(r)[0] = dcCallLong(pvm, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_INT: + PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; + INTEGER(r)[0] = dcCallInt(pvm, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_LONGLONG: + PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; + REAL(r)[0] = (double) ( dcCallLong(pvm, funcPtr) ); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_FLOAT: + PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; + REAL(r)[0] = (double) ( dcCallFloat(pvm, funcPtr) ); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_DOUBLE: + PROTECT( r = allocVector(REALSXP, 1) ); + protect_count++; + REAL(r)[0] = dcCallDouble(pvm, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_POINTER: + PROTECT( r = R_MakeExternalPtr( dcCallPointer(pvm,funcPtr), R_NilValue, R_NilValue ) ); + protect_count++; + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_VOID: + dcCallVoid(pvm,funcPtr); + if (protect_count) UNPROTECT(protect_count); + break; + default: + { + if (protect_count) + UNPROTECT(protect_count); + error("invalid return type signature"); + } + break; + } + return R_NilValue; + +} + +/* rdcCall */ + +DCCallVM* gCall; + +SEXP rdcCall(SEXP sFuncPtr, SEXP sSignature, SEXP sArgs) +{ + void* funcPtr; + const char* signature; + const char* ptr; + int i,l,protect_count; + SEXP r; + + funcPtr = R_ExternalPtrAddr(sFuncPtr); + + if (!funcPtr) error("funcptr is null"); + + signature = CHAR(STRING_ELT(sSignature,0) ); + + if (!signature) error("signature is null"); + + dcReset(gCall); + ptr = signature; + + l = LENGTH(sArgs); + i = 0; + protect_count = 0; + for(;;) { + char ch = *ptr++; + SEXP arg; + + if (ch == '\0') error("invalid signature - no return type specified"); + + if (ch == ')') break; + + if (i >= l) error("not enough arguments for given signature (arg length = %d %d %c)", l,i,ch ); + + arg = VECTOR_ELT(sArgs,i); + switch(ch) { + case DC_SIGCHAR_BOOL: + { + if ( !isLogical(arg) ) + { + PROTECT(arg = coerceVector(arg, LGLSXP)); + protect_count++; + } + dcArgBool(gCall, ( LOGICAL(arg)[0] == 0 ) ? DC_FALSE : DC_TRUE ); + // UNPROTECT(1); + break; + } + case DC_SIGCHAR_INT: + { + if ( !isInteger(arg) ) + { + PROTECT(arg = coerceVector(arg, INTSXP)); + protect_count++; + } + dcArgInt(gCall, INTEGER(arg)[0]); + // UNPROTECT(1); + break; + } + case DC_SIGCHAR_FLOAT: + { + PROTECT(arg = coerceVector(arg, REALSXP) ); + dcArgFloat( gCall, REAL(arg)[0] ); + UNPROTECT(1); + break; + } + case DC_SIGCHAR_DOUBLE: + { + if ( !isReal(arg) ) + { + PROTECT(arg = coerceVector(arg, REALSXP) ); + protect_count++; + } + dcArgDouble( gCall, REAL(arg)[0] ); + // UNPROTECT(1); + break; + } + /* + case DC_SIGCHAR_LONG: + { + PROTECT(arg = coerceVector(arg, REALSXP) ); + dcArgLong( gCall, (DClong) ( REAL(arg)[0] ) ); + UNPROTECT(1); + break; + } + */ + case DC_SIGCHAR_STRING: + { + DCpointer ptr; + if (arg == R_NilValue) ptr = (DCpointer) 0; + else if (isString(arg)) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); + else { + if (protect_count) UNPROTECT(protect_count); + error("invalid value for C string argument"); break; + } + } + case DC_SIGCHAR_POINTER: + { + DCpointer ptr; + if ( arg == R_NilValue ) ptr = (DCpointer) 0; + else if (isString(arg) ) ptr = (DCpointer) CHAR( STRING_ELT(arg,0) ); + else if (isReal(arg) ) ptr = (DCpointer) REAL(arg); + else if (isInteger(arg) ) ptr = (DCpointer) INTEGER(arg); + else if (isLogical(arg) ) ptr = (DCpointer) LOGICAL(arg); + else if (TYPEOF(arg) == EXTPTRSXP) ptr = R_ExternalPtrAddr(arg); + else { + if (protect_count) UNPROTECT(protect_count); + error("invalid signature"); break; + } + dcArgPointer(gCall, ptr); + break; + } + } + ++i; + } + + if ( i != l ) + { + if (protect_count) + UNPROTECT(protect_count); + error ("signature claims to have %d arguments while %d arguments are given", i, l); + } + + switch(*ptr) { + case DC_SIGCHAR_BOOL: + PROTECT( r = allocVector(LGLSXP, 1) ); protect_count++; + LOGICAL(r)[0] = ( dcCallBool(gCall, funcPtr) == DC_FALSE ) ? FALSE : TRUE; + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_INT: + PROTECT( r = allocVector(INTSXP, 1) ); protect_count++; + INTEGER(r)[0] = dcCallInt(gCall, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_LONG: + PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; + REAL(r)[0] = (double) ( dcCallLong(gCall, funcPtr) ); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_FLOAT: + PROTECT( r = allocVector(REALSXP, 1) ); protect_count++; + REAL(r)[0] = (double) ( dcCallFloat(gCall, funcPtr) ); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_DOUBLE: + PROTECT( r = allocVector(REALSXP, 1) ); + protect_count++; + REAL(r)[0] = dcCallDouble(gCall, funcPtr); + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_POINTER: + PROTECT( r = R_MakeExternalPtr( dcCallPointer(gCall,funcPtr), R_NilValue, R_NilValue ) ); + protect_count++; + UNPROTECT(protect_count); + return r; + case DC_SIGCHAR_VOID: + dcCallVoid(gCall,funcPtr); + if (protect_count) UNPROTECT(protect_count); + break; + default: + { + if (protect_count) + UNPROTECT(protect_count); + error("invalid return type signature"); + } + } + return R_NilValue; +} + +SEXP rdcUnpack1(SEXP ptr_x, SEXP offset, SEXP sig_x) +{ + char* ptr = ( (char*) R_ExternalPtrAddr(ptr_x) ) + INTEGER(offset)[0]; + const char* sig = CHAR(STRING_ELT(sig_x,0) ); + switch(sig[0]) + { + case DC_SIGCHAR_CHAR: return ScalarInteger( ( (unsigned char*)ptr)[0] ); + case DC_SIGCHAR_INT: return ScalarInteger( ( (int*)ptr )[0] ); + case DC_SIGCHAR_FLOAT: return ScalarReal( (double) ( (float*) ptr )[0] ); + case DC_SIGCHAR_DOUBLE: return ScalarReal( ((double*)ptr)[0] ); + default: error("invalid signature"); + } + return R_NilValue; +} + +SEXP rdcDataPtr(SEXP x, SEXP offset) +{ + void* ptr = ( ( (unsigned char*) DATAPTR(x) ) + INTEGER(offset)[0] ); + return R_MakeExternalPtr( ptr, R_NilValue, R_NilValue ); +} + +SEXP rdcMode(SEXP id) +{ + dcMode( gCall, INTEGER(id)[0] ); + dcReset( gCall ); + return R_NilValue; +} + +SEXP r_dcNewCallVM(SEXP size) +{ + return R_MakeExternalPtr( dcNewCallVM( INTEGER(size)[0] ), R_NilValue, R_NilValue ); +} + +SEXP r_dcFree(SEXP callvm) +{ + DCCallVM* pvm = R_ExternalPtrAddr(callvm); + dcFree(pvm); + return R_NilValue; +} + +SEXP r_dcMode(SEXP callvm, SEXP id) +{ + DCCallVM* pvm = R_ExternalPtrAddr(callvm); + dcMode( pvm, INTEGER(id)[0] ); + dcReset( pvm ); + return R_NilValue; +} + +/* register R to C calls */ + +R_CallMethodDef callMethods[] = +{ + {"rdcLoad", (DL_FUNC) &rdcLoad, 1}, + {"rdcFree", (DL_FUNC) &rdcFree, 1}, + {"rdcFind", (DL_FUNC) &rdcFind, 2}, + {"rdcCall", (DL_FUNC) &rdcCall, 3}, + {"rdcUnpack1", (DL_FUNC) &rdcUnpack1, 3}, + {"rdcDataPtr", (DL_FUNC) &rdcDataPtr, 2}, + {"rdcMode", (DL_FUNC) &rdcMode, 1}, + + {"dcNewCallVM", (DL_FUNC) &r_dcNewCallVM, 1}, + {"dcFree", (DL_FUNC) &r_dcFree, 1}, + {"dcCall", (DL_FUNC) &r_dcCall, 4}, + {"dcMode", (DL_FUNC) &r_dcMode, 2}, + + {NULL, NULL, 0} +}; + +void R_init_rdc(DllInfo *info) +{ + R_registerRoutines(info, NULL, callMethods, NULL, NULL); + gCall = dcNewCallVM(4096); +} + +void R_unload_rdc(DllInfo *info) +{ +} +