Table of Contents

honeysuckle

honeysuckle is a C library intended to make creating Lua bindings simpler. It was originally a core part of the honey code, but was split out into its own library because it is useful in many other contexts. It provides functions for argument parsing, table creation and processing, error throwing and handling, string wrangling, and registry operations.

hs_parse_args

void hs_parse_args(
    lua_State *L,
    ...);

Stack Modifications

[-0, +0, v][?]

Parameters

Return Value

None.

Description

This function reads arguments provided on the stack into the variables provided to it in the argument list, performing type-checking as it proceeds. If the wrong number of arguments is provided, or if there is a type mismatch between the expected type provided to this function and the actual type on the stack, it will throw an error message detailing that mismatch.

Below is a table of all of the available macros for parsing. Each function-like macro takes a single variable (not a pointer or a constant) whose type must be exactly that listed under “variable type” or undefined behavior will result. Your compiler will probably complain if there is a mismatch.

macro expected stack type variable type variable value after call
hs_bool(x) boolean bool the boolean value
hs_int(x) number, interpreted as integer lua_Integer the integer value
hs_num(x) number lua_Number the number value
hs_str(x) string char * pointer to the string data on the stack
hs_tbl(x) table int stack index of the table
hs_func(x) function int stack index of the function
hs_cfunc(x) function, interpretable as C function lua_CFunction pointer to the function
hs_user(x) userdata void * pointer to the memory block
hs_light(x) light userdata void * the pointer value
hs_nil(x) nil value int stack index of the nil value
hs_any(x) any value int stack index of the value

Example

The following would be used to create a Lua function that expects arguments like (number, string, table).

lua_Number n;
char *string;
int table_index;
hs_parse_args(L, hs_num(n), hs_str(string), hs_tbl(table_index));

hs_parse_overloaded

int hs_parse_overloaded(
    lua_State *L,
    ...);

Stack Modifications

[-0, +0, v][?]

Parameters

Return Value

The zero-based index of the overload option selected.

Description

This function allows you to create overloaded Lua bindings with a very similar syntax to hs_parse_args(). It accepts a series of hs_overload() macros that in turn accept a series of struct hs_arg construction macros, exactly as described above. It will attempt to match each provided overload option to the given arguments, returning as soon as it finds one. This function is subject to the same cautions about types discussed above.

Please note that the process of attempting to match an overload may mutate the values in the provided variables, and so you should not rely on them having the same value after a call as before, even if they do not participate in the actually selected overload.

Example

lua_Integer i;
lua_Number n;
char *string;
int choice = hs_parse_overloaded(
    L, 
    hs_overload(hs_int(i)), 
    hs_overload(hs_num(n), hs_str(string))
);
 
if (choice == 0) {
    /* n and string are undefined! */
    /* do something with i... */
}
else {
    /* i is undefined! */
    /* do something with n and string... */
}

hs_create_table

int hs_create_table(
    lua_State *L,
    ...);

Stack Modifications

[-?, +1, m][?]

Parameters

Return Value

The stack index of the created table.

Description

Create Lua tables. This function takes a series of key/value macros and constructs a table containing those keys and values. Each macro takes the form hs_[key type]_[value_type](key, value), as illustrated in the table below, Arguments to these values are passed by value, so concerns about bit alignment are not relevant here.

Macros dealing with table, function, and userdata types each take an integer. This is the stack index of the value on the Lua stack to use. These values are popped before returning. Please note both that this means that nesting tables is quite trivial (by simply calling hs_create_table() inside one of the macros) and that nesting tables in this way requires a subtable to have all of its stack-indexed keys and values pushed after any such keys or values used in an ancestor table, or else the indices needed to construct that ancestor will be modified and likely will no longer be valid.

Value Type
boolean integer number string table function C function userdata light userdata
Key Type boolean hs_bool_bool(bool, bool) hs_bool_int(bool, lua_Integer) hs_bool_num(bool, lua_Number) hs_bool_str(bool, char *) hs_bool_tbl(bool, int) hs_bool_func(bool, int) hs_bool_cfunc(bool, lua_CFunction) hs_bool_user(bool, int) hs_bool_light(bool, void *)
integer hs_int_bool(lua_Integer, bool) hs_int_int(lua_Integer, lua_Integer) hs_int_num(lua_Integer, lua_Number) hs_int_str(lua_Integer, char *) hs_int_tbl(lua_Integer, int) hs_int_func(lua_Integer, int) hs_int_cfunc(lua_Integer, lua_CFunction) hs_int_user(lua_Integer, int) hs_int_light(lua_Integer, void *)
number hs_num_bool(lua_Number, bool) hs_num_int(lua_Number, lua_Integer) hs_num_num(lua_Number, lua_Number) hs_num_str(lua_Number, char *) hs_num_tbl(lua_Number, int) hs_num_func(lua_Number, int) hs_num_cfunc(lua_Number, lua_CFunction) hs_num_user(lua_Number, int) hs_num_light(lua_Number, void *)
string hs_str_bool(char *, bool) hs_str_int(char *, lua_Integer) hs_str_num(char *, lua_Number) hs_str_str(char *, char *) hs_str_tbl(char *, int) hs_str_func(char *, int) hs_str_cfunc(char *, lua_CFunction) hs_str_user(char *, int) hs_str_light(char *, void *)
table hs_tbl_bool(int, bool) hs_tbl_int(int, lua_Integer) hs_tbl_num(int, lua_Number) hs_tbl_str(int, char *) hs_tbl_tbl(int, int) hs_tbl_func(int, int) hs_tbl_cfunc(int, lua_CFunction) hs_tbl_user(int, int) hs_tbl_light(int, void *)
function hs_func_bool(int, bool) hs_func_int(int, lua_Integer) hs_func_num(int, lua_Number) hs_func_str(int, char *) hs_func_tbl(int, int) hs_func_func(int, int) hs_func_cfunc(int, lua_CFunction) hs_func_user(int, int) hs_func_light(int, void *)
C function hs_cfunc_bool(lua_CFunction, bool) hs_cfunc_int(lua_CFunction, lua_Integer) hs_cfunc_num(lua_CFunction, lua_Number) hs_cfunc_str(lua_CFunction, char *) hs_cfunc_tbl(lua_CFunction, int) hs_cfunc_func(lua_CFunction, int) hs_cfunc_cfunc(lua_CFunction, lua_CFunction) hs_cfunc_user(lua_CFunction, int) hs_cfunc_light(lua_CFunction, void *)
userdata hs_user_bool(int, bool) hs_user_int(int, lua_Integer) hs_user_num(int, lua_Number) hs_user_str(int, char *) hs_user_tbl(int, int) hs_user_func(int, int) hs_user_cfunc(int, lua_CFunction) hs_user_user(int, int) hs_user_light(int, void *)
light userdata hs_light_bool(void *, bool) hs_light_int(void *, lua_Integer) hs_light_num(void *, lua_Number) hs_light_str(void *, char *) hs_light_tbl(void *, int) hs_light_func(void *, int) hs_light_cfunc(void *, lua_CFunction) hs_light_user(void *, int) hs_light_light(void *, void *)

Example

The following constructs the table { debugLevel=0, logfile='output.log', someUserdata=[userdata], myTable={ hello='world' } }.

lua_newuserdata(L, sizeof(char));
int user_index = lua_gettop(L);
 
hs_create_table(L,
                hs_str_int("debugLevel", 0),
                hs_str_str("logfile", "output.log"),
                hs_str_user("someUserdata", user_index),
                hs_str_tbl("myTable", hs_create_table(
                    L,
                    hs_str_str("hello", "world"),
                ));

hs_process_table

void hs_process_table(
    lua_State *L,
    int table_index,
    ...);

Stack Modifications

[-0, +0, e][?]

Parameters

Return Value

None.

Description

This function is intended to create Lua bindings that can be called like someBinding{debug=true, verbosity=6, logfile='log.txt'}. To that end, it accepts a list of value-processing macros, which are listed below. Each accepts as arguments a string to check as a key in the table, a callback function pointer (whose signature is different for each type – see below), and a void pointer to some additional data that may be used by the callbacks.

value type callback signature macro
boolean void cb(bool, void*) hs_process_bool(key, callback, data)
integer void cb(int, void*) hs_process_int(key, callback, data)
number void cb(lua_Number, void*) hs_process_num(key, callback, data)
string void cb(const char*, void*) hs_process_str(key, callback, data)

For the extremely common case of simply setting a variable, there are provided the functions hs_pt_set_bool, hs_pt_set_int, hs_pt_set_num, and hs_pt_set_str, which will cast the provided void pointer to bool, lua_Integer, lua_Number, or const char *, respectively, and then set that value to the value in the table.

This function may throw an error if the provided index is not valid or is not a table. It may trigger metamethods in extracting values.

Example

void open_logfile(const char *logfile, void *settings) {
	// do something to open and configure the logfile
}
 
// tbl_index comes from somewhere...
 
struct settings {
	bool debug;
	lua_Integer verbosity;
	lua_Number epsilon;
};
 
struct settings s;
 
hs_process_table(L, tbl_index,
        hs_process_int("verbosity", hs_pt_set_int, &(s.verbosity)),
	hs_process_bool("debug", hs_pt_set_bool, &(s.debug)),
	hs_process_str("logfile", set_logfile, &s),
	hs_process_num("epsilon", hs_pt_set_num, &(s.epsilon))
);

hs_pushstring

void hs_pushstring(
    lua_State *L,
    const char *format_string,
    ...);

Stack Modifications

[-0, +1, m][?]

Parameters

Return Value

None.

Description

This function makes it simple to push printf-formatted strings to the Lua stack. Its syntax is exactly that of sprintf, except the destination is a lua_State pointer, rather than a string buffer.

Example

const char name[] = "Kelly";
int hours = 10;
int minutes = 5;
hs_pushstring(L, "hello, %s. the current time is %d:%02d.", name, hours, minutes);

hs_vpushstring

void hs_vpushstring(
    lua_State *L,
    const char *format_string,
    va_list args);

Stack Modifications

[-0, +0, m][?]

Parameters

Return Value

None.

Description

Similar to hs_pushstring() above. Its syntax is exactly that of vsprintf, except the destination is a lua_State pointer, rather than a string buffer.

hs_throw_error

void hs_vpushstring(
    lua_State *L,
    const char *format_string,
    ...);

Stack Modifications

[-0, +0, v][?]

Parameters

Return Value

None, but by its nature this function will not return and instead makes a long jump to the current error handler.

Description

Similar to hs_pushstring() above, but pushes the string and then immediately throws an error with it. Useful for constructing complex error messages. This function may also throw a memory-related error if string creation fails.

hs_traceback

void hs_traceback(lua_State *L);

Stack Modifications

[-(0|1), +(0|1), -][?]

Parameters

Return Value

None.

Description

This function produces a call traceback string to go with an error message provided to it, or keeps the “error message” intact if it is not a string. It is generally not intended to be called manually, but rather provided to lua_pcall() as an error handler.

hs_call

int hs_call(
    lua_State *L, 
    int nargs, 
    int nret);

Stack Modifications

[-(nargs+1), +(nret|1), -][?]

Parameters

Return Value

0 on success, or else one of the Lua error codes: LUA_ERRRUN, LUA_ERRMEM, or LUA_ERRERR.

Description

This function is exactly the same as lua_pcall, with the same return values, except that it automatically pushes hs_traceback() to use as an error handler and does not accept a different error handler.

hs_rstore

int hs_rstore(lua_State *L);

Stack Modifications

[-1, +0, m][?]

Parameters

Return Value

The reference key.

Description

This is a macro wrapper around luaL_ref() that always uses the Lua registry table. It is provided for convenience.

hs_rload

void hs_rload(
    lua_State *L,
    int reference);

Stack Modifications

[-0, +1, -][?]

Parameters

Return Value

None.

Description

This is a macro wrapper around lua_rawgeti() that always gets values from the Lua registry table. It is provided for convenience.

hs_rdel

void hs_rdel(
    lua_State *L,
    int reference);

Stack Modifications

[-0, +0, -][?]

Parameters

Return Value

The reference key.

Description

This is a macro wrapper around luaL_unref() that always uses the Lua registry table. It is provided for convenience.