Files
LuaCangjia_api/lib/lua_cj_api.cpp
JianFeeeee 8aff33e402 feat: 适配 Lua 5.2.4 (lua_5.2.4 分支)
- lib/lua 替换为 Lua 5.2.4 官方源码; CMakeLists 补 lbitlib.c(5.2 linit 注册 bit32)、删 lutf8lib.c(5.2 无此文件)
- I/O 重定向机制改造: 5.2 无 lua_getextraspace → iopath 指针存入
  Registry 固定索引(IOPATH_REG_IDX=1), 回调经 get_iopath() 取回,
  free_lua 时释放 —— 该方案同样适用于更低版本
- typed interop 版本自适应: capture_result() 的 lua_isinteger 分支用
  #if LUA_VERSION_NUM >= 503 包裹, 5.2 及以下所有数字统一 CJT_NUM
- 测试跨版本适配: PackagePathConfig 接受 require 的两种返回语义;
  typed 数值断言 EXPECT_INT_OR_NUM 宏兼容有无 integer 子类型;
  大整数保真断言仅对 5.3+ 生效(5.2 经 double 必然丢精度)
- 验证: GTest 44/44 通过
2026-08-25 10:47:52 +08:00

606 lines
17 KiB
C++
Executable File
Raw Permalink 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.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);
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 = 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;
}