2012-03-02 61 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

相關問題