Files
LuaCangjia_api/lib/lua_cj_api.cpp

350 lines
9.5 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "lua_cj_api.h"
extern "C"
{
#include <string.h>
#include "errors.h"
}
using namespace std;
bool check_luastatue(lua_State *L)
{
/*检查lua状态机状况*/
if(L == NULL)
{
errno = NAPI_LUA_STACK_ERROR;
return false;
}
//分为两部分写,防止空指针访问
if(lua_status(L) != LUA_OK)
{
errno = NAPI_LUA_STATE_ERROR;
return false;
}
return true;
}
int get_errno(void) { return errno; }//获取错误码
/// @brief 加载lua文件到lua虚拟栈
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param path 需要加载的脚本的位置
/// @param name module命名卸载库时指定
/// @return 0代表正常结束-1表示异常退出
int load_lib(void *selfd,const char *path,const char *name)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
if(runner->load_lib(path,name)==-1)
return -1;
return 0;
}
/// @brief 卸载lua虚拟栈中的lua文件
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param name module命名loadlib时的name
/// @return 0代表正常结束-1表示异常退出
int unload_lib(void *selfd,const char *name)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
if(runner->unload_lib(name)==-1)
return -1;
return 0;
}
/// @brief 运行脚本(可指定入参)
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @param path 脚本的沙盒内路径
/// @param arg 脚本的入参
/// @return 0代表正常结束-1表示异常退出
int run(void *selfd,const char *path,const char *arg)
{
lua_runner* self = (lua_runner*)selfd;
//重定向输入到回调函数
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
if(runner->run(path,arg)==-1)
{
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return 0;
}
/// @brief 执行单句lua语句
/// @param selfd init_lua_runner返回的void指针
/// @param target 执行语句(字符串类型)
/// @return 成功返回0,失败返回-1,并将lua出错原因拷贝至result中
int dostring(void *selfd,const char *target){
lua_runner* self = (lua_runner*)selfd;
//重定向输入到回调函数
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
if(runner->dostring(target)==-1){
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return -1;
}
snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str());
return 0;
}
/// @brief 清理lua状态机缓存虚拟栈加载的包等
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @return 0代表正常结束-1表示异常退出
int cleanup(void *selfd)
{
lua_runner* self = (lua_runner*)selfd;
Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象
if(runner == NULL)
{
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
if(runner->clean()==-1)
return -1;
return 0;
}
/// @brief 释放lua状态机资源
/// @param self 使用init_lua_runner初始化的lua_runner结构体指针
/// @return 0代表正常结束-1表示异常退出
int free_lua(void *selfd)
{
lua_runner* self = (lua_runner*)selfd;
delete((Lua_runner*)self->lua_obj);
free(self);
return 0;
}
/*-------------重定向io操作------------------------*/
static const char *full_path(lua_State *L, int isOut)
{
iopath *r = (iopath *)lua_getextraspace(L);
static char buf[512];
snprintf(buf, sizeof(buf), "%s/%s", r->iopath, isOut ? "output" : "input");
return buf;
}
//劫持读取终端输入,触发回调
static int l_tty_read(lua_State *L)
{
iopath *r = (iopath *)lua_getextraspace(L);
if (r->funcs.io_input) r->funcs.io_input();
const char *fname = full_path(L, 0);
FILE *fp = fopen(fname, "rb");
if (!fp) return luaL_error(L, "tty read open fail: %s", fname);
fseek(fp, 0, SEEK_END);
size_t sz = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *tmp = (char*)lua_newuserdata(L, sz);
if(0 ==fread(tmp, 1, sz, fp))
return luaL_error(L, "tty fail to read input: %s", fname);
fclose(fp);
if(remove(fname) != 0)
{
errno = NAPI_RESET_INPUT_FILE_ERROR;
return luaL_error(L, "fail to reset input file: %s", fname);
}
lua_pushlstring(L, tmp, sz);
return 1;
}
//劫持到终端输出,输出结束触发回调
static int l_tty_write(lua_State *L)
{
iopath *r = (iopath *)lua_getextraspace(L);
const char *fname = full_path(L, 1);
FILE *fp = fopen(fname, "a");
if (!fp) return luaL_error(L, "tty write open fail: %s", fname);
int n = lua_gettop(L);
for (int i = 1; i <= n; ++i)
if (lua_isstring(L, i)) fputs(lua_tostring(L, i), fp);
fclose(fp);
if (r->funcs.io_output) r->funcs.io_output();
return 0;
}
static int l_print(lua_State *L) {
iopath *r = (iopath *)lua_getextraspace(L);
const char *fname = full_path(L, 1); // 输出到 output 文件
FILE *fp = fopen(fname, "a");
if (!fp) return luaL_error(L, "print redirect open fail: %s", fname);
int n = lua_gettop(L);
for (int i = 1; i <= n; ++i) {
if (i > 1) fputc('\t', fp);
const char *str = luaL_tolstring(L, i, NULL);
fputs(str, fp);
lua_pop(L, 1);
}
fputc('\n', fp);
fclose(fp);
if (r->funcs.io_output) r->funcs.io_output();
return 0;
}
/*空实现*/
static int l_tty_flush(lua_State *L)
{
(void)L;
return 0;
}
static int l_tty_close(lua_State *L)
{
(void)L;
return 0;
}
/*空实现(不需要)*/
static int l_tty_call(lua_State *L)
{
// 当尝试调用tty对象时返回自身或执行某些操作
lua_pushvalue(L, 1); // 返回对象自身
return 1;
}
static void push_tty_file(lua_State *L, int isout, const luaL_Reg *fake_tty_meta)
{
lua_newuserdata(L, sizeof(int));
luaL_newmetatable(L, isout ? "tty_out" : "tty_in");
luaL_setfuncs(L, fake_tty_meta, 0);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
// 添加__call元方法
lua_pushcfunction(L, l_tty_call);
lua_setfield(L, -2, "__call");
// 添加__tostring
lua_pushstring(L, isout ? "TTY_OUT" : "TTY_IN");
lua_setfield(L, -2, "__tostring");
lua_setmetatable(L, -2);
}
int redirecct_path(lua_State *L)
{
if(!check_luastatue(L)){
errno = NAPI_LUA_STATE_ERROR;
return -1;
}
iopath *p = (iopath*)lua_getextraspace(L);
static const luaL_Reg fake_methods[] = {
{"read", l_tty_read},
{"write", l_tty_write},
{"flush", l_tty_flush},
{"close", l_tty_close},
{NULL, NULL}
};
/* 1. 把 io.output() 换成 tty 替身 */
push_tty_file(L, 1,fake_methods);
lua_getglobal(L, "io");
lua_pushvalue(L, -2);
lua_setfield(L, -2, "output"); /* io.output = 替身 */
lua_pop(L, 2);
/* 2. 把 io.input() 换成 tty 替身 */
push_tty_file(L, 0,fake_methods);
lua_getglobal(L, "io");
lua_pushvalue(L, -2);
lua_setfield(L, -2, "input"); /* io.input = 替身 */
lua_pop(L, 2);
lua_pushcfunction(L, l_print);
lua_setglobal(L, "print");
lua_getglobal(L, "io");
lua_pushcfunction(L, l_tty_read);
lua_setfield(L, -2, "read");
lua_pushcfunction(L, l_tty_write);
lua_setfield(L, -2, "write");
lua_pop(L, 1);
return 0;
}
/*----------------重定向io操作------------------------*/
//获取对象中的返回值
char *getresult(void *selfd){lua_runner*self =(lua_runner*) selfd;return self->result;}
/// @brief 初始化lua解释器
/// @param pathio 重定向io目录
/// @param pkgpath 用户包搜索目录
/// @param input 输入回调函数
/// @param output 输出回调函数
/// @return 0正常结束-1异常退出
void *init_lua_runner(const char *pathio,const char *pkgpath,int(*input)(),int(*output)())//该函数挂载到cj构造函数中执行
{
//分配内存
lua_runner *self = (lua_runner*)malloc(sizeof(lua_runner));
//创建对象
self->lua_obj = (void*)new Lua_runner(pkgpath);
if(errno != 0)
return NULL;
if(self->lua_obj == NULL)
{
errno = NAPI_LUA_CLASS_LOST;
return NULL;
}
//提取对象
Lua_runner *runner = (Lua_runner*)self->lua_obj;
//提取lua状态机
lua_State *L = runner->get_lua_State();
if(!check_luastatue(L)){
errno = NAPI_LUA_STATE_ERROR;
return NULL;
}
iopath *io_path = (iopath*)lua_getextraspace(L);
//申请额外空间
if(pathio == NULL)
{
goto WITHOUT_REDIRECT;
}
if(io_path == NULL){
errno = NAPI_ERROR_FUNCS;
return NULL;
}
//装载重定向函数
io_path->funcs.io_input = input;
io_path->funcs.io_output = output;
//装载重定向路径
strcpy(io_path->iopath,pathio);
//注册重定向
if(redirecct_path(L)==-1){
errno = NAPI_LUA_STATE_ERROR;
return NULL;
}
WITHOUT_REDIRECT:
return (void*)self;
}