2012-03-02 52 views
11

有关这个问题的代码是在这里:https://github.com/jchester/lua-polarssl/tree/master/src为Lua包装一个C库:我如何创建函数的嵌套表?

目前我正在试图包裹PolarSSL库(http://polarssl.org)的一部分给我访问SHA-512 HMACs(luacrypto做不提供这个)。

我的目标的API的形式为:

a_sha512_hash = polarssl.hash.sha512('text') 

或更充分

local polarssl = require 'polarssl' 
local hash = polarssl.hash 

a_sha512_hash = hash.sha512('test') 

如果你是指在链接polarssl.c上面,你会看到我已经编写了包装PolarSSL代码的函数。然后,我想这样来构建功能表:

LUA_API int luaopen_polarssl(lua_State *L) { 
    static const struct luaL_Reg core[] = { 
    { NULL, NULL } 
    }; 

    static const struct luaL_Reg hash_functions[] = { 
    { "sha512", hash_sha512 }, 
    { "sha384", hash_sha384 }, 
    { NULL, NULL } 
    }; 

    static const struct luaL_Reg hmac_functions[] = { 
    { "sha512", hmac_sha512 }, 
    { "sha384", hmac_sha384 }, 
    { NULL, NULL } 
    }; 

    luaL_register(L, CORE_MOD_NAME, core); 
    luaL_register(L, HASH_MOD_NAME, hash_functions); 
    luaL_register(L, HMAC_MOD_NAME, hmac_functions); 

    return 1; 
} 

其中CORE_MOD_NAME = 'polarssl',HASH_MOD_NAME = 'polarssl.hash',HMAC_MOD_NAME = 'polarssl.hmac'。

当我运行在这个问题的顶部类似的Lua代码的测试脚本,我得到这个:

lua: test.lua:23: attempt to index global 'polarssl' (a nil value) 
stack traceback: 
    test.lua:23: in main chunk 
    [C]: ? 

我试图寻找如何实现这个module.submodule方法的例子(例如naim vs luasockets),但每个人似乎都有不同的实现方式。我完全失去了。

+0

我无法链接到naim和luasockets,因为我点击了链接上的<10点限制。 – 2012-03-02 03:18:58

+0

看起来业力就像美味的糖果一样分发,所以更新后的链接。 – 2012-03-02 03:31:40

回答

14

每个人似乎都有不同的实现方式。

这是Lua;每个人都以自己的方式行事。这是Lua最大的优势和最大的弱点:语言提供了机制,而不是政策

您需要做的第一件事就是停止使用luaL_register。是的,我知道这很方便。但你想要一些特别的东西,而luaL_register不会帮助你得到它。

你想要的是创建一个包含一个包含一个或多个函数的表的表。所以......那样做。

创建表格。

lua_newtable(L); 

这很简单。该函数将一个表推入堆栈,所以我们的堆栈现在有一个表格。这是我们将返回的表格。

现在,我们需要创建一个新的表进入旧的表。

lua_newtable(L); 

再次,容易。接下来,我们希望将我们想要的函数放入堆栈中的表中。

lua_pushcfunction(L, hash_sha512); 

所以栈有三件事情:目标表中,“散”表(我们会在第二次“点名”它),我们要投入“散列”功能表。

所以把函数放到哈希表中。

lua_setfield(L, -2, "sha512"); 

这取得堆栈顶部的任何内容,并将其设置到堆栈上-2索引处的表上名为“sha512”的字段中。这就是我们的“散列表”所在的位置。此功能完成后,它将从堆栈中删除顶层项目。这将“散列”表留在顶部。

我们可以重复该过程的第二个功能:

lua_pushcfunction(L, hash_sha384); 
lua_setfield(L, -2, "sha384"); 

现在,我们希望把“哈希”表到我们想要回表。这样做了很轻松地与其他lua_setfield电话:

​​

记住:此功能需要无论是在堆栈的顶部。在这一点上,我们想要返回的表(这将是我们模块的表)在堆栈中。

我们可以重复这一过程为“HMAC”表:

lua_newtable(L); //Create "hmac" table 
lua_pushcfunction(L, hmac_sha512); 
lua_setfield(L, -2, "sha512"); 
lua_pushcfunction(L, hmac_sha384); 
lua_setfield(L, -2, "sha384"); 
lua_setfield(L, -2, "hmac"); //Put the "hmac" table into our module table 

该模块的表现中有两个条目:“哈希”和“HMAC”。两个表都有两个功能。

我们可以用这根棍子成全局表:

lua_pushvalue(L, -1); 
lua_setfield(L, LUA_GLOBALSINDEX, "polarssl"); 

并不是每个模块制造商都想做到这一点。有些人更喜欢强迫人们使用语法,以避免污染全局命名空间。随你便。

但是你必须做的任何一种方式是返回此表。从你的luaopen函数返回1,让Lua知道有一个返回值。上面的调用​​仅用于复制表格(请记住:表格被引用,因此就像复制指针一样)。这样,当您使用lua_setfield时,副本将从堆栈中移除,而原始仍将用作返回值。

+0

谢谢。起初我有点困惑,但在纸上勾画堆叠动作让我接触到了这个过程。 – 2012-03-02 04:55:50

+3

+1因讨论'require'的返回值而引起一些麻烦...很多人似乎并没有意识到推荐的练习已经从“将模块放在全局中”转移到“返回你的模块来自require,调用者应该把它放在一个局部变量中“ – snogglethorpe 2012-03-02 22:51:41

2

不直接相关的问题,但下面的语句是不完全正确:

目前我正在试图包裹PolarSSL库的一部分(http://polarssl.org)给我访问SHA-512 HMAC(luacrypto不提供此功能)。

我不知道哪个LuaCrypto的版本你指的是,但this LuaCrypto fork确实提供了SHA-512 HMACs,以及任何其他消化由OpenSSL的自动支持的类型。只是通过"sha512"作为摘要类型:

hmac.digest("sha512", message, key) 

文档状态只有支持的消化类型的一部分,完整的列表可以通过调用crypto.list("digests")检索。

table.foreach(crypto.list("digests"), print) 

当我仔细想想,即使原来LuaCrypto应该支持SHA-512。

+0

谢谢,我没有意识到它。但是,我正在使用不包装SHA512的“主”叉。我选择封装PolarSSL,因为它很小,API非常简单 - 每个模块都是独立的,可以独立编译。例如,我只编译了SHA512/384模块。总大小:22kb。 – 2012-03-03 01:36:33

+0

这确实是一个非常合理的尺寸!如果您想要将Lua嵌入到密码功能中,看起来不错。 – 2012-03-03 09:43:32

相关问题