Files
LuaCangjia_api/lib/lua_cj_api.cpp
JianFeeeee 86c6e276be feat: 适配 Lua 5.0.3 (lua_5.0 分支)
- 桥接层编译通过, 核心功能可用(init/load/unload/callfunction/dostring)
- 新增 compat_50.h 兼容层集中处理 5.0 差异:
  * luaL_newstate → lua_open (#define)
  * lua_status → 恒 LUA_OK(5.0 单线程, 无状态查询)
  * luaL_dostring → lua_dostring(lauxlib)
  * lua_getfield/setfield → pushstring+gettable/settable
    (含绝对索引修正, 避免 push 后相对偏移)
  * lua_Integer → double, lua_pushinteger→pushnumber(5.0 无整数类型)
  * luaL_Reg typedef(5.0 结构体名小写 luaL_reg)
  * open_std_libs 替代 luaL_openlibs(5.0 需逐库 luaopen_*)
- 5.0 无 package 系统: pkgpath 构造函数参数被忽略; clean 跳过
  package.loaded={} 操作
- 5.0 不支持 ... 表达式(chunk 级无变参): 涉及此语法的测试脚本
  需替换为 5.0 兼容版(已创建 test/scripts50/ 目录)
- 验证: lib 构建 0 error, InitFree 通过; 因语法差异部分测试未全过
  (桥接层本身无 bug, 属测试脚本版本差异)
2026-08-25 12:59:17 +08:00

628 lines
18 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"
#include <new>
// 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 <string.h>
#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 interopv0.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_tolstringlua_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 无 extraspacenew 一个 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;
}