lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Hi folks,

the whole binding issue (tolua vs SWIG etc) went through my mind recently, and I came up with this atrocity for Lua-5.0 and Linux. It is of course seriously non-portable, but similar hacks should be rather easy for other OS and machines. The C stuff below has to be compiled and registered with
|lua_register(l, "capply", l_capply);
lua_register(l, "dlopen", l_dlopen);
|
Then, one can write stuff like

|dl = dlopen("/lib/libc.so.6")
capply("", dl.srand48)
print("random: ", capply("I", dl.lrand48)) end

dl2 = dlopen("/usr/lib/libm.so")
print("sin:", capply("dD", dl2.sin, 3.14))

|The generation of the spec string could be wrapped up with a simple parser of C header files and then one could make the whole thing a bit more typesafe by combining the spec string, a C function and capply into one closure for each bound C function.

What do you think about it?

Ciao, Dolfi

|/*** feed to  gcc -O (and maybe -fomit-frame-pointer) ***/

#include <lua.h>
#include <math.h>
#include <lauxlib.h>
#include "glua.h"

#include <dlfcn.h>

int l_dlgettable(lua_State *l)
{   const char *name, **reg;
   void       *dl = *(void**)lua_touserdata(l, 1), *value;
   int        i;

   if(!lua_isstring(l, 2))
       glua_error("dlgettable expects a string index");
   else if(!(value = dlsym(dl, name = lua_tostring(l, -1))))
       glua_error("dlsym couldn't access symbol %s", name);
   else if(!strcmp(name, "registry"))
   {   int cnt = 0;
       reg = (const char**)value;
       lua_newtable(l);
       for(i = 0; name = reg[i]; i++)
           if(value = dlsym(dl, name))
{ lua_pushvalue(l, -1); lua_pushstring(l, name); lua_pushcfunction(l, value); lua_settable(l, -3); }
           else
fprintf(stderr, "%s%s", cnt++?", ":"registry symbols undefined: ", name);
       if(cnt) fprintf(stderr, "\n");
   }
   else if(!strcmp(name, "label"))
   {   if(value = dlsym(dl, name))
           lua_pushstring(l, *(char**)value);
       else
           lua_pushnil(l);
   }
   else
       lua_pushlightuserdata(l, value);
   return 1;
}

int l_dlclose(lua_State *l)
{   dlclose(lua_touserdata(l, -1));
   return 0;
}

int l_dlopen(lua_State *l)
{   void       *dl;
   const char *name;

   if(!lua_isstring(l, -1))
       luaL_error(l, "dlopen expects a string argument");
   else
   {   name = lua_tostring(l, -1);
       dl = dlopen(name, RTLD_NOW);
       if(!dl)
       {   luaL_error("dlopen: %s\n", dlerror());  }
       else
       {   *(void**)lua_newuserdata(l, 4) = dl;
           lua_newtable(l);
lua_pushstring(l, "__gc"); lua_pushcfunction(l, l_dlclose); lua_settable(l, -3); lua_pushstring(l, "__index"); lua_pushcfunction(l, l_dlgettable); lua_settable(l, -3);
           lua_setmetatable(l, -2);
           fprintf(stderr, "dlopen succeeded\n");
       }
   }
   return 1;
}

#define MAXARG 64
int l_capply(lua_State *l)
{   const char             *spec, *specp;
   int                       c = 0, n, top, nword;
   register unsigned long __d0, __d1, __d2; /* dummies */
   static void           *arg[MAXARG], **arge = arg+MAXARG;
   void           *fn, **argp;
   double           dres;
   long           lres;

   spec = luaL_checkstring(l, 1);
   fn = lua_touserdata(l, 2);
for(specp = spec, argp = arg, n = 3, top = lua_gettop(l); argp<arge && n<=top; n++, specp++)
   switch(c = *specp)
   {   case 'd': *((double*)argp)++ = lua_tonumber(l, n); break;
       case 'i': *((signed long *)argp)++ = lua_tonumber(l, n); break;
       case 'u': *((unsigned long *)argp)++ = lua_tonumber(l, n); break;
       case 's': *((const char**)argp)++ = lua_tostring(l, n); break;
       case 'p': *((void**)argp)++ = lua_touserdata(l, n); break;
       default : goto LEAVE;
   }
LEAVE:
   if(argp>arge)
       luaL_error(l, "capply: argument buffer size %d exceeded", MAXARG);
   if(n>top)
luaL_error(l, "capply: too few args on lua stack for spec '%s'\n", spec);
   nword = argp-arg;
   __asm__ __volatile__
   ("movl      %%esp, %%edi\n\t"
    "subl      %6,%%edi\n\t"
    "movl      %%edi,%%esp\n\t"
    "cld\n\t"
    "rep\n\t"
    "movsl\n\t"
    "call      *%7\n\t"
    "movl      %%edi,%%esp\n\t"
    "movl    %%eax, %3\n\t"
    : "=&c" (__d0), "=&S" (__d1), "=&D" (__d2), "=m" (lres)
    : "0" (nword), "1" (arg), "r" (nword<<2), "a" (fn)
    : "cc");
   switch(*specp)
   {   case 'D':
       __asm__ __volatile__ ("fstpl %0": "=m" (dres));
       lua_pushnumber(l, dres); return 1;
   case 'I':
       lua_pushnumber(l, lres); return 1;
   case 'U':
       lua_pushnumber(l, (unsigned long)lres); return 1;
   case 'S':
       lua_pushstring(l, (unsigned char *)lres); return 1;
   default:
       return 0;
   }
}
|