Mercurial > pub > dyncall > bindings
view lua/luadyncall/src/ldyncall.c @ 37:8c8f848131c6
- version bump
- better doc
- made calling convention mode reset by default, as only way to specify convention used is via signature string
author | Tassilo Philipp |
---|---|
date | Mon, 13 Apr 2020 20:08:54 +0200 |
parents | 0cfcc391201f |
children |
line wrap: on
line source
#include <stddef.h> #include "lua.h" #include "lauxlib.h" #include "dyncall.h" #include "dyncall_signature.h" DCCallVM* g_pCallVM = NULL; /** * lua syntax: * * dodyncall( address, signature, ... ) * **/ int lua_dodyncall(lua_State *L) { void* f; const char *callsignature, *s; int top = lua_gettop(L); if (top < 2) return luaL_error(L,"missing arguments #1 'addr' and #2 'signature'"); if ( lua_iscfunction(L,1) ) f = (void*) lua_tocfunction(L, 1); else if (lua_islightuserdata(L,1) ) f = lua_touserdata(L, 1); else if (lua_isnumber(L,1) ) f = (void*) lua_tointeger(L, 1); else return luaL_argerror(L, 1, "expected a cfunction, userdata or number"); s = callsignature = luaL_checkstring(L,2); /* parse mode */ // dcMode( g_pCallVM, DC_CALL_C_DEFAULT ); dcReset( g_pCallVM ); char ch; int p = 3; int ptr = 0; while ( (ch = *s++) != DC_SIGCHAR_ENDARG) { if (p > top) return luaL_error(L,"need more arguments (call signature is '%s')", callsignature ); if (ptr == 0) { switch(ch) { case '*': ptr++; continue; case DC_SIGCHAR_BOOL: dcArgBool(g_pCallVM, (DCbool) luaL_checkint(L, p) ); break; case DC_SIGCHAR_CHAR: case DC_SIGCHAR_UCHAR: dcArgChar(g_pCallVM, (DCchar) luaL_checkint(L, p) ); break; case DC_SIGCHAR_SHORT: case DC_SIGCHAR_USHORT: dcArgShort(g_pCallVM, (DCshort) luaL_checkint(L, p) ); break; case DC_SIGCHAR_INT: case DC_SIGCHAR_UINT: dcArgInt(g_pCallVM, (DCint) luaL_checknumber(L, p) ); break; case DC_SIGCHAR_LONG: case DC_SIGCHAR_ULONG: dcArgLong(g_pCallVM, (DClong) luaL_checknumber(L, p) ); break; case DC_SIGCHAR_LONGLONG: case DC_SIGCHAR_ULONGLONG: dcArgLongLong(g_pCallVM, (DClonglong) luaL_checknumber(L, p) ); break; case DC_SIGCHAR_FLOAT: dcArgFloat(g_pCallVM, (DCfloat) luaL_checknumber(L, p) ); break; case DC_SIGCHAR_DOUBLE: dcArgDouble(g_pCallVM, (DCdouble) luaL_checknumber(L, p) ); break; case DC_SIGCHAR_POINTER: dcArgPointer(g_pCallVM, (DCpointer) lua_topointer(L, p) ); break; case DC_SIGCHAR_STRING: dcArgPointer(g_pCallVM, (DCpointer) lua_tostring(L, p) ); break; default: return luaL_error(L, "invalid typecode '%c' in call signature '%s'", s[0], callsignature); } } else { /* pointer types */ switch(ch) { case '*': ptr++; continue; case '<': { const char* begin = s; while ( (ch = *s++) != '>' ) ; const char* end = s; switch( lua_type(L,p) ) { case LUA_TNUMBER: dcArgPointer(g_pCallVM, (DCpointer) (ptrdiff_t) lua_tonumber(L, p) ); break; case LUA_TTABLE: lua_pushvalue(L, p); // 1 lua_pushliteral(L, "pointer"); lua_gettable(L, -2); // 2 if ( !lua_isuserdata(L, -1) ) luaL_error(L, "pointer type mismatch at argument #%d", p); dcArgPointer(g_pCallVM, (DCpointer) lua_touserdata(L, -1) ); lua_pop(L, 2); break; case LUA_TLIGHTUSERDATA: case LUA_TUSERDATA: dcArgPointer(g_pCallVM, (DCpointer) lua_topointer(L, p) ); break; default: luaL_error(L, "pointer type mismatch at argument #%d", p); break; } } break; case DC_SIGCHAR_BOOL: case DC_SIGCHAR_CHAR: if ( lua_isstring(L, p) ) { dcArgPointer(g_pCallVM, (DCpointer) lua_tostring(L, p) ); break; } case DC_SIGCHAR_UCHAR: case DC_SIGCHAR_SHORT: case DC_SIGCHAR_USHORT: case DC_SIGCHAR_INT: case DC_SIGCHAR_UINT: case DC_SIGCHAR_LONG: case DC_SIGCHAR_ULONG: case DC_SIGCHAR_LONGLONG: case DC_SIGCHAR_ULONGLONG: case DC_SIGCHAR_FLOAT: case DC_SIGCHAR_DOUBLE: case DC_SIGCHAR_POINTER: case DC_SIGCHAR_STRING: case DC_SIGCHAR_VOID: if ( lua_istable(L, p) ) { lua_pushvalue(L, p); // 1 lua_pushliteral(L, "pointer"); lua_gettable(L, -2); // 2 if ( !lua_isuserdata(L, -1) ) luaL_error(L, "pointer type mismatch at argument #%d", p); dcArgPointer(g_pCallVM, (DCpointer) lua_touserdata(L, -1) ); lua_pop(L, 2); } else dcArgPointer(g_pCallVM, (DCpointer) lua_topointer(L, p) ); ptr = 0; break; default: return luaL_error(L, "invalid signature"); } } ++p; } if (top >= p) luaL_error(L,"too many arguments for given signature, expected %d but received %d" , p-3, top-2 ); switch(*s++) { case DC_SIGCHAR_VOID: dcCallVoid(g_pCallVM, f); return 0; case DC_SIGCHAR_BOOL: lua_pushboolean( L, (int) dcCallBool(g_pCallVM, f) ); break; case DC_SIGCHAR_CHAR: case DC_SIGCHAR_UCHAR: lua_pushnumber( L, (lua_Number) ( dcCallChar(g_pCallVM,f) ) ); break; case DC_SIGCHAR_SHORT: case DC_SIGCHAR_USHORT: lua_pushnumber( L, (lua_Number)( dcCallShort(g_pCallVM, f) ) ); break; case DC_SIGCHAR_INT: case DC_SIGCHAR_UINT: lua_pushnumber( L, (lua_Number)( dcCallInt(g_pCallVM, f) ) ); break; case DC_SIGCHAR_LONG: case DC_SIGCHAR_ULONG: lua_pushnumber( L, (lua_Number)( dcCallLong(g_pCallVM, f) ) ); break; case DC_SIGCHAR_LONGLONG: case DC_SIGCHAR_ULONGLONG: lua_pushnumber( L, (lua_Number)( dcCallLongLong(g_pCallVM, f) ) ); break; case DC_SIGCHAR_FLOAT: lua_pushnumber( L, (lua_Number) dcCallFloat(g_pCallVM, f) ); break; case DC_SIGCHAR_DOUBLE: lua_pushnumber( L, (lua_Number) dcCallDouble(g_pCallVM, f) ); break; case DC_SIGCHAR_STRING: lua_pushstring( L, (const char*) dcCallPointer(g_pCallVM, f) ); break; case DC_SIGCHAR_POINTER: lua_pushlightuserdata( L, dcCallPointer(g_pCallVM, f) ); break; case '*': switch(*s++) { case DC_SIGCHAR_UCHAR: case DC_SIGCHAR_CHAR: lua_pushstring( L, dcCallPointer(g_pCallVM, f) ); break; default: lua_pushlightuserdata( L, dcCallPointer(g_pCallVM, f) ); break; } break; default: return luaL_error(L, "invalid signature"); } return 1; } int topointer(lua_State* L) { lua_pushlightuserdata(L, (void*) (ptrdiff_t) luaL_checkint(L, 1) ); return 1; } static const struct luaL_Reg luareg_dyncall[] = { { "dodyncall", lua_dodyncall }, { "topointer", topointer }, { NULL, NULL } /* { "NewCallVM", lua_dcNewCallVM }, { "Mode", lua_dcMode }, { "Reset", lua_dcReset }, { "ArgBool", lua_dcBool }, { "ArgChar", lua_dcChar }, { "ArgShort", lua_dcShort }, { "ArgInt", lua_dcInt }, { "ArgLong", lua_dcLong }, { "ArgLongLong", lua_dcLongLong }, */ }; void lua_setmetainfo(lua_State *L) { lua_pushliteral(L, "_COPYRIGHT"); lua_pushliteral(L, "Copyright (C) 2010 Dyncall Project"); lua_settable(L, -3); lua_pushliteral(L, "_DESCRIPTION"); lua_pushliteral(L, "lua bindings for dyncall libraries"); lua_settable(L, -3); lua_pushliteral(L, "_VERSION"); lua_pushliteral(L, "0.1"); lua_settable(L, -3); } LUA_API int luaopen_ldyncall(lua_State* L) { g_pCallVM = dcNewCallVM(4096); luaL_register(L, "ldyncall", luareg_dyncall); lua_setmetainfo(L); return 1; }