我的第一份供lua调用的c模块

时间:2023-03-09 15:45:50
我的第一份供lua调用的c模块
#include <stdio.h>
#include <string> #include <direct.h>
#include <windows.h>
#include <io.h> extern "C" {
#include "D:\myPath\lua\5.3\include\lua.h"
#include "D:\myPath\lua\5.3\include\lauxlib.h"
#include "D:\myPath\lua\5.3\include\lualib.h"
}
#pragma comment(lib,"D:\\myPath\\lua\\5.3\\lib\\Lua53.lib")// 该模块和lua解释器都要使用动态链接
// 因为这是lua解释器也要用到的库,使用静态链接会报错 multiple Lua VMs detected #define LUA_VERSION_NUM 503 // 使用static 防止名字污染
static int pusherror(lua_State *L, const char *info) // lua函数返回错误信息就是这么来的
{
lua_pushnil(L); // lua函数不是一出错就先返回 nil + info 的模式么?
if (info == NULL)
lua_pushstring(L, strerror(errno));
else
lua_pushfstring(L, "%s: %s", info, strerror(errno));
lua_pushinteger(L, errno);
return 3;
}
// 获取当前目录 因为会用到系统有关的目录api,所以cl编译时 运行时库选择 /MD
static int get_dir (lua_State *L)
{
#ifdef NO_GETCWD
lua_pushnil(L);
lua_pushstring(L, "Function 'getcwd' not provided by system");
return 2;
#else
char *path = NULL;
/* Passing (NULL, 0) is not guaranteed to work. Use a temp buffer and size instead. */
size_t size = MAX_PATH; /* initial buffer size */
int result;
while (1)
{
path = (char *)realloc(path, size);
if (!path) /* failed to allocate */
return pusherror(L, "get_dir realloc() failed");
if (_getcwd(path, size) != NULL)
{
/* success, push the path to the Lua stack */
lua_pushstring(L, path);
result = 1;
break;
}
if (errno != ERANGE) { /* unexpected error */ //就是说expected的error 是ERANGE,
result = pusherror(L, "get_dir getcwd() failed");
break;
}
/* ERANGE = insufficient buffer capacity, double size and retry */
size *= 2;
}
free(path);
return result;
#endif
} static int l_split(lua_State*L){
const char* s = luaL_checkstring(L,-2);
const char* sep = luaL_checkstring(L,-1);
lua_newtable(L);
const char* e = s;
int i = 1;
while((e= strchr(s,*sep))!=NULL){
if(e-s==0){s=e+1;continue;} // 避免连续的*sep导致压入空串
lua_pushlstring(L, s, e-s);
lua_rawseti(L, -2, i++);
s = e+1;
}
lua_pushstring(L, s);
lua_rawseti(L, -2, i); return 1;
}
static int gettable(lua_State *L)
{
//lua_setfield lua_seti lua_settable luaL_ref
//lua_getfield lua_geti lua_gettable luaL_unref
// luaL_unref是删除键值对 luaL_ref是自动生成唯一键
lua_newtable(L);
char value[32] = {0};
char key[10] = {0};
for(int i = 1; i <= 5; i++)
{
sprintf(value, "value: %d", i);
lua_pushstring(L, value);
lua_seti(L, -2, i);
} for(int i = 6; i <= 10; ++i)
{
sprintf(key, "key %d", i);
sprintf(value, "value %d", i);
lua_pushstring(L, value);
lua_setfield(L, -2, key);
} for(int i = 11; i <= 15; ++i)
{
sprintf(key, "key %d", i);
sprintf(value, "value %d", i);
lua_pushstring(L, key);
lua_pushstring(L, value);
lua_settable(L, -3);
} for(int i = 16; i <= 20; ++i)
{
sprintf(value, "value %d", i);
lua_pushstring(L, value);
luaL_ref(L, -2); // 这个 不用管key, luaL_ref是自动生成唯一的key
} return 1;
} // assumes the table is on the top of stack
static int printtable(lua_State *L)
{
if(!lua_istable(L, -1))return 0;
lua_len(L, -1);
int nlen = lua_tointeger(L, -1);
lua_pop(L, 1);// 注意 这里不是索引而是数量
printf("table length:%d\n",nlen);
for(int i = 1; i <= nlen; ++i)
{
lua_geti(L, -1, i);
int t = lua_type(L, -1);
switch(t)
{
case LUA_TSTRING:
printf("%s\n", lua_tostring(L, -1));
break;
case LUA_TNUMBER:
{
if(lua_isinteger(L, -1))printf("%d\n", lua_tointeger(L, -1) );
else printf("%f\n", lua_tonumber(L, -1));
}
break;
default:printf("other type\n");
}
lua_pop(L, 1);
}
return 0;
}
static const struct luaL_Reg mylib[] =
{
{"currentdir", get_dir},
{"l_split", split},
{"gettable", gettable},
{"printtable",printtable},
{NULL, NULL},
}; extern "C" __declspec(dllexport) int luaopen_mylib(lua_State *L) // 必须是luaopen_+dll名的形式
//requre(name)=>会找name.dll 找到name.dll 中的 luaopen_name导出函数
{
//luaL_register(L,"mylib",mylib); // 已弃用 会污染全局namespace //前面还可以加一些元表信息
//设置 __gc __index等写法
luaL_newlib(L, mylib);
// lua_setglobal(L, "mylib"); // 有了这一句就可以不用mylib = require("mylib")了 lua_pushliteral(L, "Copyright (C) 2003-2016 Kepler Project");
lua_setfield(L, -2, "_COPYRIGHT");
lua_pushliteral(L, "1.0 ");
lua_setfield(L, -2, "_VERSION");
return 1;
}