// // Created by koncord on 09.01.19. // #include #include #include "FFI.hpp" FFI::FFI(ScriptFunc func, char retFormat, const char *argFormat, ...) { std::va_list argList; va_start(argList, argFormat); fnPtr = func; setArguments(argFormat, argList); setRetType(retFormat); va_end(argList); } void FFI::setArguments(const std::string &format, va_list argList) { cifInitialized = false; va_list vaList; va_copy(vaList, argList); resize(format.size()); for (size_t i = 0; i < format.size(); ++i) { switch (format[i]) { case 'v': break; case 's': // const char* setArgument(i, (const char*) va_arg(vaList, const char*)); break; case 'c': setArgument(i, (int8_t) va_arg(vaList, int)); break; case 'C': setArgument(i, (uint8_t) va_arg(vaList, int)); break; case 'h': setArgument(i, (int16_t) va_arg(vaList, int)); break; case 'H': setArgument(i, (uint16_t) va_arg(vaList, int)); break; case 'i': setArgument(i, va_arg(vaList, int32_t)); break; case 'I': setArgument(i, va_arg(vaList, uint32_t)); break; case 'l': setArgument(i, va_arg(vaList, int64_t)); break; case 'L': setArgument(i, va_arg(vaList, uint64_t)); break; case 'd': case 'f': setArgument(i, va_arg(vaList, double)); break; case 'p': setArgument(i, va_arg(vaList, void*)); break; case 'b': // bool setArgument(i, (bool) (va_arg(vaList, int) == 1)); break; default: break; } } va_end(vaList); } void FFI::setRetType(char type) { cifInitialized = false; retType = formatToFFIType(type); } void FFI::setFunctionPtr(ScriptFunc func) { cifInitialized = false; fnPtr = func; } #include "Types.hpp" ffi_type *FFI::formatToFFIType(char type) { switch (type) { case 'v': return CToFFIType(); case 's': return CToFFIType(); case 'c': return CToFFIType(); case 'C': return CToFFIType(); case 'h': return CToFFIType(); case 'H': return CToFFIType(); case 'i': return CToFFIType(); case 'I': return CToFFIType(); case 'l': return CToFFIType(); case 'L': return CToFFIType(); case 'f': case 'd': return CToFFIType(); case 'p': return CToFFIType(); case 'b': // bool return CToFFIType(); default: throw std::invalid_argument(std::string("unknown argument type \'") + type + '\''); } } void FFI::resize(size_t size) { types.resize(size); ptrs.resize(size); argsStore.resize(size); } RetType FFI::call() { if (!cifInitialized) { cifInitialized = true; if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, (unsigned int) types.size(), retType, types.data()) != FFI_OK) throw std::runtime_error("Whoops! Cannot prepare CIF!"); } ffi_arg retVal; ffi_call(&cif, FFI_FN(fnPtr), &retVal, ptrs.data()); return retVal; }