diff lua/luadyncall/src/ldyncall.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/lua/luadyncall/src/ldyncall.c	Thu Mar 19 22:26:28 2015 +0100
@@ -0,0 +1,263 @@
+#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;
+}
+