Lua C modules: confused about including members - c

I am trying to register a Lua C module that I need to use like this.
local harfbuzz = require 'harfbuzz'
-- initialize blob
local blob = harfbuzz.Blob.new(…)
print(blob:length())
My understanding is that I should create a new table and add a metatable to it with the methods, and then add that table as a member Blob to the top-level lib table.
Here is the relevant snippet of code in my C file. I am not very sure what to include in the register_blob function. I tried a few things and they did not work.
static const struct luaL_Reg blob_methods[] = {
{ "length", blob_length },
{"__gc", blob_destroy },
{ NULL, NULL },
};
static const struct luaL_Reg blob_functions[] = {
{ "new", blob_new },
{ NULL, NULL }
};
static const struct luaL_Reg lib_table [] = {
{"version", get_harfbuzz_version},
{NULL, NULL}
};
int register_blob(lua_State *L) {
// QUESTION: What should I include here
}
int luaopen_luaharfbuzz (lua_State *L) {
lua_newtable(L);
register_blob(L);
luaL_setfuncs(L, lib_table, 0);
return 1;
}

What register_blob does really depends on what new_blob needs to do. The two feed into one another.
Given your use case, new_blob needs to create new objects, and those new objects have metatable members equal to your blob_methods table. So, what new_blob needs to do is:
Create a table/userdata to be returned.
Assign that table/userdata a metatable built from the contents of blob_methods table.
Do whatever other initialization work is needed on the object.
Return the object.
So what your register_blob code needs to do is build the metatable that you intend to use in step 2, then store it somewhere that new_blob can easily access it. But also somewhere that noone else can. Or at least, noone outside of C code.
Lua being well designed, it has a place for storing exactly this kind of data. It's called the Lua registry table. The registry acts like a global table. But it can only be access from C; Lua code can't touch it (well, unless you use the debug library. Or pass the registry table to Lua).
The idiomatic way (as I understand it) that the registry is used is that every C module stakes out its own table index in the registry. So your luaopen_luaharfbuzz function would create a table and store that into a key in the registry. The key would probably some string, likely named after your module. And you put all your private stuff into that table.
So your register_blob function would:
Create the table that will be used as the metatable for blob objects.
Use luaL_setfuncs to set the blob_methods into the newly created table.
Get the harfbuzz table from the registry.
Put the newly created table into a known key in the harfbuzz table from the registry.
That way, new_blob knows exactly where to go to get the metatable to use.

Related

How do I declare global variables in Pact lang?

I'm writing a smart contract and I want to declare global variables. I want the functions in my smart contract to be able to access and update these variables.
For example, in Solidity I can do this as follows:
pragma solidity ^0.5.0;
contract SolidityTest {
uint someSmartContractVar; // State variable
constructor() public {
someSmartContractVar = 10; // Setting the variable
}
...
}
I see the coin contract makes use of defconst here:
(defconst COIN_CHARSET CHARSET_LATIN1
"The default coin contract character set")
This approach is good for variables that need to be accessible by the rest of the contract, but I don't think I can change the values of these variables at some later point.
One possibility is creating a table named "global-variables" and storing the specific variables there. So then the functions can access and change these variables via table reads and updates. For example:
(defschema global-variable-schema
someSmartContractVar:decimal)
(deftable global-variables:{global-variable-schema})
(defconst GLOBAL_VAR_KEYNAME "global-vars")
(defun constructor:string ()
(insert global-variables GLOBAL_VAR_KEYNAME
{ 'someSmartContractVar: 10.0 }
)
"Global variables set"
)
(defun get-someSmartContractVar:decimal ()
(at "someSmartContractVar" (read global-variables GLOBAL_VAR_KEYNAME))
)
Is this the recommended approach for this type of use case?
Great question and that solution should work!
I don't know of any other practical way to do it.

Referencing a Struct not using the variable's name

Hello I have a swift file that contains arrays of tuples that I reference with my app. For example, my structure looks like:
struct workoutDict {
static var bicepWorkouts = [("Barbell Curl","Bicep",0,"3x10"), ("x","x",3,"x")]
}
I have a global variable named eqID. For example, eqID = "bicepWorkouts"
There is part of my code where I attempt to call this dictionary. Normally I would use: workoutDict.bicepWorkouts and this works fine, but I have other workouts such as barbellWorkouts in my dictionary so i let the user select "bicepWorkouts", "barbellWorkouts" ect based on user input and need to use that to reference my struct.
Right now i have
//Call the global variable to get what workout to look for
code = eqID
let ourWorkouts = workoutDict.code
which should set ourWorkouts = workoutDict.bicepWorkouts when our eqID is set to that, but it keeps giving me the error that workoutDict does not contain the code when I use that reference.
I tried researching alternate methods of referencing structs but I couldn't find anything. Any help would be appreciated!
You should create yet another dictionary to store the names:
struct workoutDict {
static var dicts = [ "bicepWorkouts": bicepWorkouts, "barbellWorkouts": barbellWorkouts ]
}
Then you can access the sub dictionaries by:
workoutDict.dicts[eqlID]

Configurable custom code

Our customer provided source code has portions of code that will be executed based on tool type. A sample code portion is given below. The function has common portions and tool specific(hardware platform) portions. The code is written in C and runs in VxWorks. Addition or deletion of new tool type has code modification. The customer wants addition or deletion new tool type with minimal code change and testing effort
int vsp_recv(char *const recv_text)
{
int rc = 0;
const int type = get_tool_type();
// Common Code
if (MODEL_CR == type)
{
rc = beamoff(recv_text);
}
else
{
rc = vsp_set(recv_text);
}
return(rc);
}
Is it the right technique to separate the code to two methods as given below, keep them in separate source files and define separate make files to generate tool specific binary? Is there any better ways to do this?
Tool type MODEL_CR code
int vsp_recv_tool_speccific(char *const recv_text)
{
return beamoff(recv_text);
}
Tool type MODEL_CV code
int vsp_recv_tool_speccific(char *const recv_text)
{
return vsp_set(recv_text);
}
Refactored method
int vsp_recv(char *const recv_text)
{
int rc = 0;
const int type = get_tool_type();
// Common Code
rc = vsp_recv_tool_speccific(recv_text);
}
Define a shared library for each tool and a configuration file that defines what functions get called for each tool. Load the shared libraries at startup and provide a signal catcher to reload if the configuration file changes.
the OPs question (and posted code) says that 3 places will need to be modified.
the function: get_tool_type()
the header file with the definitions of MODEL_CV, MODEL_CR, etc
the if-then-else list.
were it me, I would implement a table of function pointers, have get_tool_type() return an index into that table. Then all the if/then/else code would become a single statement that invokes a function from the table.
Then any updates would be additions to the table, modifications to 'get_too_type(), and the additional functions likebeam_off()`
The loss of a tool type would not require any code change.
the addition of a tool type would require appending an entry to the table, mod to get_tool_type() to recognize the new tool, and the new function to process the new tool type.
Of course, this could result in code that is never executed.

Wrapping a C library for Lua: how do I create nested tables of functions?

The code related to this question is here: https://github.com/jchester/lua-polarssl/tree/master/src
Currently I'm trying to wrap one part of the PolarSSL library (http://polarssl.org) to give me access to SHA-512 HMACs (luacrypto does not provide this).
The API I'm aiming for is of the form:
a_sha512_hash = polarssl.hash.sha512('text')
or more fully
local polarssl = require 'polarssl'
local hash = polarssl.hash
a_sha512_hash = hash.sha512('test')
If you refer to polarssl.c in the link above, you'll see I've written functions that wrap PolarSSL code. Then I'm trying to build the function tables thus:
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;
}
Where CORE_MOD_NAME = 'polarssl', HASH_MOD_NAME = 'polarssl.hash', HMAC_MOD_NAME = 'polarssl.hmac'.
When I run a test script similar to the Lua code at the top of this question, I get this:
lua: test.lua:23: attempt to index global 'polarssl' (a nil value)
stack traceback:
test.lua:23: in main chunk
[C]: ?
I've tried looking for examples of how to achieve this module.submodule approach (eg naim vs luasockets), but everyone seems to have a different way of achieving it. I'm completely lost.
everyone seems to have a different way of achieving it.
That's Lua; everyone does it their own way. It's Lua's greatest strength and greatest weakness: the language provides mechanisms, not policies.
The first thing you need to do is stop using luaL_register. Yes, I know it's convenient. But you want something special, and luaL_register isn't going to help you get it.
What you want is to create a table that contains a table that contains one or more functions. So... do that.
Create a table.
lua_newtable(L);
That was easy. The function pushes a table on to the stack, so our stack now has a table on top of it. This is the table we will return.
Now, we need to create a new table to go inside the old one.
lua_newtable(L);
Again, easy. Next, we want to put the function we want to go into that table on the stack.
lua_pushcfunction(L, hash_sha512);
So the stack has three things: the destination table, the "hash" table (we'll get to "naming" it in a second), and the function we want to put into the "hash" table.
So put the function into the hash table.
lua_setfield(L, -2, "sha512");
This takes whatever is on top of the stack and sets it into the field named "sha512" on the table at the -2 index on the stack. That's where our "hash" table is. After this function completes, it removes the top item from the stack. This leaves the "hash" table at the top.
We can repeat the process for the second function:
lua_pushcfunction(L, hash_sha384);
lua_setfield(L, -2, "sha384");
Now, we want to put the "hash" table into the table we want to return. That's done easily enough with another lua_setfield call:
lua_setfield(L, -2, "hash");
Remember: this function takes whatever is on top of the stack. At this point, the table we want to return (which will be our module's table) is on the stack.
We can repeat this process for the "hmac" table:
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
The module's table now has two entries in it: "hash" and "hmac". Both are tables with two functions in them.
We can stick it into the global table with this:
lua_pushvalue(L, -1);
lua_setfield(L, LUA_GLOBALSINDEX, "polarssl");
Not every module maker wants to do that. Some prefer to force people to use the local polarssl = require "polarssl" syntax, to avoid polluting the global namespace. It's up to you.
But what you must do either way is to return this table. Return 1 from your luaopen function, to let Lua know that there is one return value. The lua_pushvalue call above exists for the sole purpose of copying the table (remember: tables are referenced, so it's like copying a pointer). That way, when you use lua_setfield, the copy gets removed from the stack, while the original remains to be used as a return value.
Not directly related to the question, but the following statement is not entirely true:
Currently I'm trying to wrap one part of the PolarSSL library (http://polarssl.org) to give me access to SHA-512 HMACs (luacrypto does not provide this).
I do not know which version of LuaCrypto are you referring to, but this LuaCrypto fork does provide SHA-512 HMACs, and also any other digest type supported by OpenSSL automatically. Just pass "sha512" as the digest type:
hmac.digest("sha512", message, key)
The documentation states only a part of the supported digest types, the complete list can be retrieved by calling crypto.list("digests").
table.foreach(crypto.list("digests"), print)
When I think about it, even original LuaCrypto should support SHA-512.

Lua C api : How to load lua files defined as modules?

I have the following lua script :
module("modoo",package.seeall)
foo=1
bar={12,34}
Which works fine using the cli, such as :
> dofile "mod_modoo.lua"
> =modoo.foo
1
> =modoo
table: 0x86ce058
As far as I understood, it works like a table, but whenever I try loading it as a table, a nil value is pushed onto the stack. Every other table works normally.
I thought using lua_getglobal wouldn't work with modules, but I couldn't find the proper way to load it either ; how should I do it ?
Load Lua modules with require like lua.c does. See http://www.lua.org/source/5.1/lua.c.html#dolibrary
Instead of using module and dofile, it is better practice in Lua 5.1 to simply return a table representing your module when the script is run. All functions and variables should be declared as local within the module script so that the returned table provides the only access point and no globals from other modules are trampled. The module should be imported using require as follows.
mod_modoo.lua:
return { foo = 1, bar = { 12, 34 } }
modoo_test.lua:
> local modoo = require "mod_modoo"
However, it is often nice to bring the module table (i.e. modoo) in as a global without explicitly assigning it. To do so, assign the module table a global reference in addition to returning it from the script. In that case, the module can be used as follows:
mod_modoo.lua:
modoo = { foo = 1, bar = { 12, 34 } }
return modoo
modoo_test.lua:
> require "mod_modoo"
> print(modoo.foo)
1
See the Lua Module Function Critiqued article for more information on the matter.

Resources