lua5.1.4中实现自定义require的loader函数

来源:互联网 发布:淘宝客服聊天记录技巧 编辑:程序博客网 时间:2024/05/01 21:47

刚开始以为只是简单的把自己的C函数,替换到package.loaders[2](索引2是lua的文件加载器)里面就OK了,实际上也是这样的,但是这样的代价就是文件搜索啊,一堆一堆的判断啊都要自己做,因为这些lua本身已经实现了,所以肯定直接拿来用之。但问题来了,发现直接简单的package.loaders[2]=myloadfunc是失败的。会抛出这个错误:

luaL_error(L, LUA_QL("package.%s") " must be a string", pname);

好吧,我碰到个没碰到的问题:环境,之前这个东西概念的一直不清楚的,我也没想去马上去了解。于是Google,能搜到的唯一有用的东西就是云风博客上的那篇文章,里面说要先获取函数的环境,然后再设置给自己的函数。。。。。。。完全不懂,说的太简单,毕竟人家完全不考虑我们这些入门级选手。去找API,发现有个getfenv,然后为了方便直接用dostring来设置看看,结果失败。打印后发现,不管获取什么的环境都是一样的表。无奈之下去了解环境的概念,大概搞明白了,于是发现根据那个概念,似乎怎么都获取不到,毕竟你要在函数里面才能获取到环境,或者返回一个闭包才能获取到函数里面的环境。但是最好还是想到云风那个做法,于是想试试CAPI是否能获取到环境表。答案是肯定的,CAPI就能获取到package.loaders[2]的环境表。但是因为CAPI操作不熟练,搞了半天都没搞好,其实是搞错了设置table的方法,把自己的CFunction作为键放到loaders里面去了。找了半天,再去看看以前弄的操作,终于找到原因。改好后又出现重复加载文件的错误,调试了半天发现是自己写错文件名,该死的低级错误。最终终于一切正常,泪流满面。有了自定义的require,加上之前实现的lua_Reader,完全可以解析加密过的lua文件。

鉴于网上关于lua的资料实在太少,放出来大家分享一下。

luajit2.0.1通用

[cpp] view plaincopy
  1. typedef int (*manual_load_file_func)(lua_State* L, const char* filename);  
  2. typedef int (*readable_func)(const char* filename);  

[cpp] view plaincopy
  1. static manual_load_file_func manul_load_file = NULL;  
  2. static readable_func readablefunc = NULL;  
  3.   
  4. static void loaderror(lua_State *L, const char *filename)  
  5. {  
  6.     luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",  
  7.         lua_tostring(L, 1), filename, lua_tostring(L, -1));  
  8. }  
  9.   
  10. static const char *pushnexttemplate(lua_State *L, const char *path)  
  11. {  
  12.     const char *l;  
  13.     while (*path == *LUA_PATHSEP) path++;  /* skip separators */  
  14.     if (*path == '\0'return NULL;  /* no more templates */  
  15.     l = strchr(path, *LUA_PATHSEP);  /* find next separator */  
  16.     if (l == NULL) l = path + strlen(path);  
  17.     lua_pushlstring(L, path, (size_t)(l - path));  /* template */  
  18.     return l;  
  19. }  
  20.   
  21. static const char *searchpath (lua_State *L, const char *name,  
  22.                                const char *path, const char *sep,  
  23.                                const char *dirsep)  
  24. {  
  25.     luaL_Buffer msg;  /* to build error message */  
  26.     luaL_buffinit(L, &msg);  
  27.     if (*sep != '\0')  /* non-empty separator? */  
  28.         name = luaL_gsub(L, name, sep, dirsep);  /* replace it by 'dirsep' */  
  29.     while ((path = pushnexttemplate(L, path)) != NULL) {  
  30.         const char *filename = luaL_gsub(L, lua_tostring(L, -1),  
  31.             LUA_PATH_MARK, name);  
  32.         lua_remove(L, -2);  /* remove path template */  
  33.         if (readablefunc && readablefunc(filename))  /* does file exist and is readable? */  
  34.             return filename;  /* return that file name */  
  35.         lua_pushfstring(L, "\n\tno file " LUA_QS, filename);  
  36.         lua_remove(L, -2);  /* remove file name */  
  37.         luaL_addvalue(&msg);  /* concatenate error msg. entry */  
  38.     }  
  39.     luaL_pushresult(&msg);  /* create error message */  
  40.     return NULL;  /* not found */  
  41. }  
  42.   
  43. static const char *findfile(lua_State *L, const char *name,  
  44.                             const char *pname)  
  45. {  
  46.     const char *path;  
  47.     lua_getfield(L, LUA_ENVIRONINDEX, pname);  
  48.     path = lua_tostring(L, -1);  
  49.     if (path == NULL)  
  50.         luaL_error(L, LUA_QL("package.%s"" must be a string", pname);  
  51.     return searchpath(L, name, path, ".", LUA_DIRSEP);  
  52. }  
  53.   
  54. static int lua_file_from_manual_func(lua_State *L)  
  55. {  
  56.     const char *filename;  
  57.     const char *name = luaL_checkstring(L, 1);  
  58.     filename = findfile(L, name, "path");  
  59.     if (filename == NULL) return 1;  /* library not found in this path */  
  60.     if (manul_load_file && manul_load_file(L, filename) != 0)  
  61.         loaderror(L, filename);  
  62.     return 1;  /* library loaded successfully */  
  63. }  
  64.   
  65. void InitManualFunction(lua_State *L, manual_load_file_func loadfilefunc, readable_func readalbefunc_in )  
  66. {  
  67.     manul_load_file = loadfilefunc;  
  68.     readablefunc = readalbefunc_in;  
  69.   
  70.     lua_getglobal(L,"package");  
  71.     lua_getfield(L,-1,"loaders");//package.loaders  
  72.     lua_pushnumber(L, 2);  
  73.     lua_gettable(L, -2);//package.loaders[2]  
  74.     lua_pushnumber(L,2);//先把索引压栈,呆会用来设置C函数到这个索引位置  
  75.     lua_pushcfunction(L,lua_file_from_manual_func);//压入自己的C函数  
  76.     lua_getfenv(L,-3);//获取旧函数的环境表  
  77.     int ret=lua_setfenv(L,-2);//设置到新函数  
  78.     lua_settable(L,-4);//替换旧函数  
  79.     lua_pop(L,3);//清理堆栈  
  80. }  

使用:

[cpp] view plaincopy
  1.     lua_State* L = luaL_newstate();  
  2.     luaL_openlibs(L);  
  3.   
  4.     InitManualFunction(L, my_load_file, readable);  
  5. <span style="white-space:pre">  </span>int status =luaL_dofile(L,"Test.lua");  
  6. <span style="white-space:pre">  </span>if (status && !lua_isnil(L, -1))  
  7.     {  
  8.         const char* error = lua_tostring(L, -1);  
  9.         printf("调用脚本出错,错误信息:%s\n",error);  
  10.         lua_pop(L, 1);  
  11.     }  
  12.   
  13.     lua_close(L);  

0 0
原创粉丝点击