lua-users home
lua-l archive

binding issues

[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;
 }
}
|

AltStyle によって変換されたページ (->オリジナル) /