1
0
mirror of https://github.com/lxsang/antd-lua-plugin synced 2025-02-13 15:02:48 +01:00

ffi via libffi (contd)

This commit is contained in:
lxsang 2019-04-30 20:09:07 +02:00
parent ef51f7f700
commit 0ac583407d
6 changed files with 397 additions and 1 deletions

View File

@ -3,7 +3,7 @@ include var.mk
PL_NAME=lua-api
PLUGINS=$(PL_NAME).$(EXT)
LLIBS=wurl.llib ulib.llib ann.llib stmr.llib #pibot.llib
LLIBS=wurl.llib ulib.llib ann.llib stmr.llib ffi.llib #pibot.llib
OBJS = $(PLUGINS_BASE)/plugin.o

6
lib/ffi/Makefile Normal file
View File

@ -0,0 +1,6 @@
include ../../../../var.mk
LIB_NAME=ffi.$(LIB_EXT)
LIB_OBJ= ffi.o
LIB_CONF= -lffi
include ../../lib.mk

6
lib/ffi/example/Makefile Normal file
View File

@ -0,0 +1,6 @@
CC = gcc
main: lib.o
$(CC) -shared lib.o -o libtest.so
%.o: %.c
$(CC) -fPIC -c $< -o $@

View File

@ -0,0 +1,45 @@
local ffi = require("ffi")
local path = "/home/mrsang/Desktop/testffi/libtest.so"
local lib = nil
local fn = nil
local rettype = nil
local argtype = nil
if ffi then
-- now ffi exist
-- try to load the test library
lib = ffi.dlopen(path)
if lib then
-- now try to lookup for the greet function
echo("looking for greet")
fn = ffi.dlsym(lib,"greet")
if fn then
-- now the function found
-- tried to called it
rettype = ffi.atomic_type(0) -- void
if rettype then
argtype = ffi.atomic_type(20) -- pointer
if(argtype) then
-- call the function
local r = ffi.call(rettype, {argtype}, fn, {"hello world"})
if r then
echo("BIG SUCCESS")
else
echo("HELL FAIL")
end
else
echo("argtype not found")
end
else
echo("return type not found")
end
else
echo("unable to find greet")
end
ffi.dlclose(lib)
else
echo("unable to load the lib")
end
else
echo("cannot find ffi")
end
echo("end the day")

6
lib/ffi/example/lib.c Normal file
View File

@ -0,0 +1,6 @@
#include <stdio.h>
void greet(const char* msg)
{
printf("%s\n", msg);
}

333
lib/ffi/ffi.c Normal file
View File

@ -0,0 +1,333 @@
/*
This lib use libffi
so libffi should be installed in the system
*/
#include "../lualib.h"
#include "../../lua-api.h"
#include "utils.h"
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
// for library access
#include <dlfcn.h>
// ffi
#include <ffi.h>
#define MAX_FN_ARGC 32
// define atomic type
typedef enum ffi_atomic_t {
L_FFI_TYPE_VOID,
L_FFI_TYPE_UINT8,
L_FFI_TYPE_SINT8,
L_FFI_TYPE_UINT16,
L_FFI_TYPE_SINT16,
L_FFI_TYPE_UINT32,
L_FFI_TYPE_SINT32,
L_FFI_TYPE_UINT64,
L_FFI_TYPE_SINT64,
L_FFI_TYPE_FLOAT,
L_FFI_TYPE_DOUBLE,
L_FFI_TYPE_UCHAR,
L_FFI_TYPE_SCHAR,
L_FFI_TYPE_USHORT,
L_FFI_TYPE_SSHORT,
L_FFI_TYPE_UINT,
L_FFI_TYPE_SINT,
L_FFI_TYPE_ULONG,
L_FFI_TYPE_SLONG,
L_FFI_TYPE_LONGDOUBLE,
L_FFI_TYPE_POINTER
};
static const ffi_type* ffi_atomic_type_ptrs[] =
{
&ffi_type_void,
&ffi_type_uint8,
&ffi_type_sint8,
&ffi_type_uint16,
&ffi_type_sint16,
&ffi_type_uint32,
&ffi_type_sint32,
&ffi_type_uint64,
&ffi_type_sint64,
&ffi_type_float,
&ffi_type_double,
&ffi_type_uchar,
&ffi_type_schar,
&ffi_type_ushort,
&ffi_type_sshort,
&ffi_type_uint,
&ffi_type_sint,
&ffi_type_ulong,
&ffi_type_slong,
&ffi_type_longdouble,
&ffi_type_pointer,
NULL
};
static int l_dlopen(lua_State* L)
{
const char* path = luaL_checkstring(L,1);
void* lib_handle = dlopen(path, RTLD_LAZY);
if(!lib_handle)
{
lua_pushnil(L);
return 1;
}
// push the handle pointer to lua
lua_pushlightuserdata(L, lib_handle);
return 1;
}
static int l_dlclose(lua_State* L)
{
LOG("%s\n","Begin close");
void* handle = lua_touserdata(L,1);
if(!handle)
{
LOG("%s\n","Cannot close that thing, handle not found");
lua_pushboolean(L,0);
return 1;
}
LOG("%s\n","the handle is found");
dlclose(handle);
lua_pushboolean(L,1);
return 1;
}
static int l_dlsym(lua_State* L)
{
char* error;
void* handle = lua_touserdata(L,1);
const char* fname = luaL_checkstring(L,2);
void* fn = dlsym(handle, fname);
if ((error = dlerror()) != NULL)
{
lua_pushnil(L);
return 1;
}
lua_pushlightuserdata(L, fn);
return 1;
}
static int l_ffi_prepare(lua_State* L, ffi_type** argvtype, int idx)
{
// argument count not more than 64
int argc = 0;
// now loop through the args type table, then fill the argvtype
lua_pushvalue(L,idx);
// stack now contains: -1 => table
lua_pushnil(L);
// stack now contains: -1 => nil, -2 => table
while(lua_next(L, -2))
{
// stack now contains: -1 => value; -2 key; -3 table
argvtype[argc] = lua_touserdata(L, -1);
argc++;
// pop the value, leaving the original key
lua_pop(L,1);
// stack now contains: -1 key; -2 table
}
// lua_next return 0, it popout the key at -1, leaving the table
// so, popout the table
argvtype[argc] = NULL;
lua_pop(L,1);
return argc;
}
void * parser_value(lua_State* L, int idx, ffi_type* ffitype)
{
lua_Number * value;
switch(ffitype->type)
{
case FFI_TYPE_VOID : return NULL;
case FFI_TYPE_POINTER:
// TODO: need to fix this to universal pointer
return lua_tostring(L, idx);
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
value = (lua_Number*) malloc(ffitype->size);
*value = lua_tonumber(L,idx);
break;
case FFI_TYPE_STRUCT:
// not implemented yet
return NULL;
break;
default: return NULL;
}
return (void*)value;
}
static void parser_arguments(lua_State* L, int idx, void** argv, ffi_type** argvtype)
{
// loop through table
lua_pushvalue(L,idx);
// stack now contains: -1 => table
lua_pushnil(L);
int i = 0;
// stack now contains: -1 => nil, -2 => table
while(lua_next(L, -2))
{
// stack now contains: -1 => value; -2 key; -3 table
argv[i] = parser_value(L, -1, argvtype[i]);
i++;
// pop the value, leaving the original key
lua_pop(L,1);
// stack now contains: -1 key; -2 table
}
// lua_next return 0, it popout the key at -1, leaving the table
// so, popout the table
lua_pop(L,1);
}
static void free_arguments(void** argv, ffi_type** argvtype)
{
ffi_type * ffitype;
for(int i = 0; argvtype[i] != NULL; i++)
{
ffitype = argvtype[i];
switch (ffitype->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_LONGDOUBLE:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
if(argv[i]) free(argv[i]);
break;
default: break;
}
}
}
static int l_ffi_call(lua_State* L)
{
ffi_type * argvtype[MAX_FN_ARGC];
ffi_type * rettype = lua_touserdata(L,1);
int argc = l_ffi_prepare(L, argvtype, 2);
printf("Argument count %d\n", argc);
printf("ret type: %d\n", rettype->type);
void* argv[MAX_FN_ARGC];
ffi_arg ret;
ffi_cif cif;
if(ffi_prep_cif(&cif,FFI_DEFAULT_ABI,argc,rettype,argvtype) == FFI_OK)
{
void(* fn)(const char*) = lua_touserdata(L,3);
if(!fn)
{
LOG("%s\n", "function not found");
lua_pushboolean(L,0);
return 1;
}
// the arguments of the function is at 4th position on the stack
// we need to loop through this table and check if argument type
// is correct to the definition in argvtype
//argv = (void**)malloc(sizeof(void*)*argc);
//ret = (void*)malloc(rettype->size);
// now parser the argument
parser_arguments(L,4,argv,argvtype);
// test
char* tmp = (char*)argv[0];
argv[0] = &tmp;
ffi_call(&cif,fn, &ret, argv);
free_arguments(argv, argvtype);
//if(argv) free(argv);
//if(ret) free(ret);
lua_pushboolean(L,1);
return 1;
}
printf("fail to prepare %d\n");
lua_pushboolean(L,0);
return 1;
}
static int l_ffi_atomic_type(lua_State* L)
{
int etype = (int)luaL_checknumber(L,1);
ffi_type* type = NULL;
if(etype > L_FFI_TYPE_POINTER)
{
lua_pushnil(L);
return 1;
}
type = ffi_atomic_type_ptrs[etype];
lua_pushlightuserdata(L,type);
return 1;
}
static int l_ffi_struct(lua_State* L)
{
// 1st element in the stack is the
// struct table
int len = lua_rawlen(L,1);
ffi_type* cstruct = lua_newuserdata(L, (len+2) * sizeof(ffi_type) );
int i = 0;
cstruct->size = cstruct->alignment = 0;
cstruct->type = FFI_TYPE_STRUCT;
// now iterate the lua table to pick all the type
lua_pushvalue(L,1);
// stack now contains: -1 => table
lua_pushnil(L);
// stack now contains: -1 => nil, -2 => table
while(lua_next(L, -2))
{
// stack now contains: -1 => value; -2 key; -3 table
cstruct->elements[i] = lua_touserdata(L, -1);
i++;
// pop the value, leaving the original key
lua_pop(L,1);
// stack now contains: -1 key; -2 table
}
// null terminated elements
cstruct->elements[i] = NULL;
// lua_next return 0, it popout the key at -1, leaving the table
// so, popout the table
lua_pop(L,1);
// the top of the stack is now the new user data
return 1;
}
static const struct luaL_Reg _lib [] = {
{"dlopen", l_dlopen},
{"dlsym",l_dlsym},
{"dlclose",l_dlclose},
{"call",l_ffi_call},
{"atomic_type", l_ffi_atomic_type},
{"struct", l_ffi_struct },
{NULL,NULL}
};
int luaopen_ffi(lua_State *L)
{
luaL_newlib(L, _lib);
return 1;
}