#include "lua_cj_api.h" #include // Lua 5.1 兼容:无 LUA_OK 宏,成功返回值为 0 #ifndef LUA_OK #define LUA_OK 0 #endif // Lua 5.2/5.1 无 lua_getextraspace,改用 Registry 固定索引存储 iopath 指针 #define IOPATH_REG_IDX 1 extern "C" { #include #include "errors.h" } using namespace std; bool check_luastatue(lua_State *L) { /*检查lua状态机状况*/ if(L == NULL) { errno = LUAERR_LUA_STACK; return false; } //分为两部分写,防止空指针访问 if(lua_status(L) != LUA_OK) { errno = LUAERR_LUA_STATE; return false; } return true; } int get_errno(void) { return errno; }//获取错误码 // 同步 typed 结果:把 Lua_runner 的 last_result_* 拷贝到外层 lua_runner 结构体 static void sync_typed_result(lua_runner *self, Lua_runner *runner) { self->tresult_type = runner->last_result_type; self->tresult_int = runner->last_result_int; self->tresult_num = runner->last_result_num; self->tresult_bool = runner->last_result_bool; } /// @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 = LUAERR_LUA_STATE; 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 = LUAERR_LUA_STATE; 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 = LUAERR_LUA_STATE; 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文件到内存:加载文件、执行顶层代码、捕获返回的函数并存入 Registry,供后续 callfunction 多次调用 /// @param selfd init_lua_runner返回的void指针 /// @param path 需要加载的文件路径 /// @param name 函数名称(callfunction/unloadfunction时使用) /// @return 0代表正常结束,-1表示异常退出 int loadfunction(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 = LUAERR_LUA_STATE; return -1; } if(runner->loadfunction(path,name)==-1) return -1; return 0; } /// @brief 卸载预加载的函数(释放 Registry 引用) /// @param selfd init_lua_runner返回的void指针 /// @param name loadfunction加载时的函数名称 /// @return 0代表正常结束,-1表示异常退出 int unloadfunction(void *selfd,const char *name) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj;//还原对象 if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->unloadfunction(name)==-1) return -1; return 0; } /// @brief 按名称调用已预加载的函数(从 Registry 取出,不消耗该函数,可重复调用) /// @param selfd init_lua_runner返回的void指针 /// @param name loadfunction加载时的函数名称 /// @param arg 传递给函数的单参数(可为NULL) /// @return 成功返回0,失败返回-1,并将lua出错原因拷贝至result中 int callfunction(void *selfd,const char *name,const char *arg) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->callfunction(name,arg)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } /*-------------typed interop(v0.2.2)------------------------*/ int callfunction_int(void *selfd,const char *name,long long val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->callfunction_int(name,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int callfunction_num(void *selfd,const char *name,double val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->callfunction_num(name,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int callfunction_bool(void *selfd,const char *name,int val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->callfunction_bool(name,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int callfunction_void(void *selfd,const char *name) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->callfunction_void(name)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int run_int(void *selfd,const char *path,long long val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->run_int(path,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int run_num(void *selfd,const char *path,double val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->run_num(path,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int run_bool(void *selfd,const char *path,int val) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->run_bool(path,val)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int run_void(void *selfd,const char *path) { lua_runner* self = (lua_runner*)selfd; Lua_runner *runner = (Lua_runner*)self->lua_obj; if(runner == NULL) { errno = LUAERR_LUA_STATE; return -1; } if(runner->run_void(path)==-1){ snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); return -1; } snprintf(self->result,MAX_RESULT,"%s",runner->reslt.c_str()); sync_typed_result(self, runner); return 0; } int result_type(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_type;} long long result_int(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_int;} double result_num(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_num;} int result_bool(void *selfd){lua_runner*self =(lua_runner*)selfd;return self->tresult_bool;} /*-------------typed interop------------------------*/ /// @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 = LUAERR_LUA_STATE; 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 = LUAERR_LUA_STATE; 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; // 释放 Registry 中的 iopath(若存在) Lua_runner *runner = (Lua_runner*)self->lua_obj; if (runner != NULL) { lua_State *L = runner->get_lua_State(); if (L != NULL) { lua_rawgeti(L, LUA_REGISTRYINDEX, IOPATH_REG_IDX); iopath *p = (iopath*)lua_touserdata(L, -1); lua_pop(L, 1); delete p; // NULL 也安全 } } delete((Lua_runner*)self->lua_obj); free(self); return 0; } /*-------------重定向io操作------------------------*/ /* Lua 5.2/5.1 无 lua_getextraspace,改用 Registry 固定索引存储 iopath 指针 */ static iopath *get_iopath(lua_State *L) { lua_rawgeti(L, LUA_REGISTRYINDEX, IOPATH_REG_IDX); iopath *r = (iopath *)lua_touserdata(L, -1); lua_pop(L, 1); return r; } static const char *full_path(lua_State *L, int isOut) { iopath *r = get_iopath(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 = get_iopath(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 = LUAERR_RESET_INPUT_FILE; 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 = get_iopath(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 = get_iopath(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); #if LUA_VERSION_NUM >= 502 const char *str = luaL_tolstring(L, i, NULL); #else /* Lua 5.1 无 luaL_tolstring:lua_tostring 对非字符串做 tostring 元方法转换, 转换失败(如 table/function)时返回 NULL,退化为类型名 */ const char *str = lua_tostring(L, i); if (!str) str = lua_typename(L, lua_type(L, i)); #endif fputs(str, fp); #if LUA_VERSION_NUM >= 502 lua_pop(L, 1); /* luaL_tolstring 压入的结果需弹出;lua_tostring 不压栈 */ #endif } 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"); #if LUA_VERSION_NUM >= 502 luaL_setfuncs(L, fake_tty_meta, 0); #else /* Lua 5.1 无 luaL_setfuncs:手动注册函数表 */ for (const luaL_Reg *l = fake_tty_meta; l->name; l++) { lua_pushcfunction(L, l->func); lua_setfield(L, -2, l->name); } #endif 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 = LUAERR_LUA_STATE; return -1; } iopath *p = get_iopath(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)); // typed interop 字段初始化 self->tresult_type = CJT_NIL; self->tresult_int = 0; self->tresult_num = 0.0; self->tresult_bool = 0; //创建对象 self->lua_obj = (void*)new Lua_runner(pkgpath); if(errno != 0) return NULL; if(self->lua_obj == NULL) { errno = LUAERR_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 = LUAERR_LUA_STATE; return NULL; } // Lua 5.2/5.1 无 extraspace:new 一个 iopath 存入 Registry iopath *io_path = new (std::nothrow) iopath(); if(pathio == NULL) { delete io_path; goto WITHOUT_REDIRECT; } if(io_path == NULL){ errno = LUAERR_CLASS_LOST; return NULL; } //装载重定向函数 io_path->funcs.io_input = input; io_path->funcs.io_output = output; //装载重定向路径 strcpy(io_path->iopath,pathio); //存入 Registry 固定索引供回调取用 lua_pushlightuserdata(L, (void*)io_path); lua_rawseti(L, LUA_REGISTRYINDEX, IOPATH_REG_IDX); //注册重定向 if(redirecct_path(L)==-1){ errno = LUAERR_LUA_STATE; return NULL; } WITHOUT_REDIRECT: return (void*)self; }