diff options
author | sanine-a <sanine.not@pm.me> | 2021-05-23 14:17:27 -0500 |
---|---|---|
committer | sanine-a <sanine.not@pm.me> | 2021-05-23 14:17:27 -0500 |
commit | 4dc4d9f1d20a73d1e4c399a56c86bf70589b13d9 (patch) | |
tree | c1d35031608e22e8ed187c8d3330a3dd57be2c41 |
create README.md and .gitignore
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README.md | 284 |
2 files changed, 285 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/README.md b/README.md new file mode 100644 index 0000000..de37ca5 --- /dev/null +++ b/README.md @@ -0,0 +1,284 @@ +--- +layout: base +title: honeysuckle README +--- + +honeysuckle +=========== + +A pure C library to make writing Lua bindings simple. honeysuckle provides +functions to make argument parsing, table operations, error creation and +handling, string wrangling, and registry operations easy and straightforward +from within your C code. + +Table of contents +----------------- + +- [Installation](#installation) +- [Usage](#usage) +- [Development](#development) +- [License](#license) +- [Footer](#footer) + +Installation +------------ + +[(Back to top)](#table-of-contents) + +Just copy `honeysuckle.h` and `honeysuckle.c` into your project. +**honeysuckle** depends on the Lua libraries, so make sure you have them +installed before using. + +Usage +----- + +[(Back to top)](#table-of-contents) + +- [Type constants](#type-constants) +- [Argument parsing](#argument-parsing) + - [Overloading](#overloading) +- [Table construction](#table-construction) + - [Enums](#enums) +- [Table processing](#table-processing) +- [Errors and error handling](#errors-and-error-handling) +- [String wrangling](#string-wrangling) +- [Registry values](#registry-values) + +### Type constants + +[(Back to top)](#table-of-contents) + +These constants are used when honeysuckle needs to know a type to expect. + +- `HS_BOOL` - booleans +- `HS_INT` - integers +- `HS_NUM` - numbers (double by default) +- `HS_STR` - strings +- `HS_TBL` - tables +- `HS_FUNC` - any function +- `HS_CFUNC` - C functions specifically +- `HS_USER` - lua full userdata +- `HS_LIGHT` - lua light userdata +- `HS_NIL` - lua's nil +- `HS_ANY` - any type + +`hs_type_to_string()` takes as argument a single type constant and returns a +const string representing the type. + +### Argument parsing + +[(Back to top)](#table-of-contents) + +`hs_parse_args()` is the primary argument-parsing function. It accepts as +arguments a lua_State pointer, any number of alternating type constant and +pointer pairs, and finally `HS_END` to close the arguments. This function +performs typechecking and in case of an error throws with helpful error +messages. `hs_parse_args_fast()` does not perform typechecking, and as a +result has much less friendly error messages. + +`HS_TBL`, `HS_FUNC`, `HS_NIL`, and `HS_ANY` do not take a pointer, and are +simply used to confirm the presence of an argument on the stack. + +```C +int some_lua_binding(lua_State *L) +{ + bool b; + int i; + lua_Number n; + char *str; + void* user; + hs_parse_args(L, + HS_BOOL, &b, + HS_INT, &i, + HS_NUM, &n, + HS_STR, &str, + HS_USER, &user, + HS_END); + // do something... + return 1; +} +``` + +#### Overloading + +There is another function, `hs_parse_overloaded()`, that permits overloaded +argument parsing. Its syntax is exactly as `hs_parse_args()` except that after +each `HS_END` you may provide another argument list, and after the final +argument list you must provide another `HS_END`. This function throws an error +only if none of the argument lists match the provided arguments. + +```C +int overloaded_lua_binding(lua_State *L) +{ + int i; + char *str; + int choice = hs_parse_overloaded(L, + HS_INT, &i, HS_END, + HS_STR, &str, HS_END, + HS_END); + if (choice == 0) { + // do something with i + // str remains unassigned!! + } + else { + // choice == 1, do something with str + // i remains unassigned!! + } + return 0; +} +``` + +### Table construction + +[(Back to top)](#table-of-contents) + +`hs_create_table()` takes a lua_State pointer, some number of string key/type +constant/value triplets, and finally `HS_END`. It returns the stack index of +the newly created table. Most of the type constants expect their associated +type (e.g. `HS_INT` expects an `int`, `HS_CFUNC` expects `lua_CFunction`, +etc.) but `HS_FUNC` and `HS_TBL` expect an integer stack index. `hs_create_ +table()` automatically pops any stack indices provided to it. + +```C +int *ptr; // some pointer + +hs_create_table(L, + "intVal", HS_INT, 4, + "numVal", HS_NUM, 6.0f, + "tableVal", HS_TBL, hs_create_table(L, + "subTableCFunc", HS_CFUNC, some_lua_binding, + "subTableString", HS_STR, "i'm a string!", + HS_END), + "lightUserdataVal", HS_LIGHT, (void *)ptr, + HS_END); +``` + +#### Enums + +`hs_create_enum()` takes a lua_State pointer, some number of string/integer +pairs, and finally `HS_END`. It creates a table in which, for each string/int +pair `tbl[string] = int` and `tbl[int] = string` and returns the stack index +of said table. `hs_string_to_enum()` uses such a table to convert a string +literal to enum value and `hs_enum_to_string()` converts enums to strings. In +case the value does not exist, converting to a string results in NULL and +converting to an enum results in a negative value. + +```C +enum { VALUE_1, VALUE_2, VALUE_3 } example_t; + +int index = hs_create_enum(L, + "one", VALUE_1, + "two", VALUE_2, + "three", VALUE_3, + HS_END); + +example_t e = hs_string_to_enum(L, index, "one"); // VALUE_1 +char *str = hs_enum_to_string(L, index, VALUE_3); // "three" +``` + +### Table processing + +[(Back to top)](#table-of-contents) + +`hs_process_table()` is intended for creating lua bindings that can be called +like `set_config{ debug=true, verbosity=2, logfile='run.log' }`. It can only operate on stringly-keyed values. + +```C +void set_verbosity(int value, void *data) { // set verbosity level } +void set_debug(bool value, void *data) { // set debug } +void set_logfile(char *value, void *data) { // set log filename } +void process_any_key(int stack_index, void *data) { // do something } + +// tbl_index comes from somewhere... + +hs_process_table(L, tbl_index, NULL, + "verbosity", HS_INT, set_verbosity, + "debug", HS_BOOL, set_debug, + "logfile", HS_STR, set_logfile, + "extraData", HS_ANY, process_any_key, + HS_END); +``` + +### Errors and error handling + +[(Back to top)](#table-of-contents) + +`hs_throw_error()` constructs and throws error messages like printf. + +```C +hs_throw_error(L, "ERROR: %d is not within range", 10); +``` + +`hs_traceback()` can be supplied to `lua_pcall()` to get a helpful stack trace +error message: + +```C +lua_pushcfunction(L, hs_traceback); +int tr_pos = lua_gettop(); + +// push function +// push n arguments +int result = lua_pcall(L, nargs, nret, tr_pos); +``` + +`hs_call()` performs the above, accepting simply a lua_State pointer, int +nargs, and int nret as arguments. Alternatively, you can use `hs_call_args()` +which provides the same helpful, contained error messages as `hs_call()` but +takes arguments explicitly in the call for both function arguments and +returns: + +```C +// some_function accepts int, str and returns number, boolean +lua_pushcfunction(L, some_function); + +lua_Number n; +bool b; +hs_call_args(L, + HS_INT, 4, HS_STR, "hello", HS_END, + HS_NUM, &n, HS_BOOL, &b, HS_END); +``` + +### String wrangling + +[(Back to top)](#table-of-contents) + +`hs_pushstring()` allows you to push string values using printf format +strings. + +```C +hs_pushstring(L, "hello there, %s. I hear the current time is %d:%02d", "dylan", 10, 5); +``` + +### Registry values + +[(Back to top)](#table-of-contents) + +honeysuckle provides three macros, `hs_rstore()`, `hs_rload()`, and `hs_ +rdel()` to make registry access easier. These are mostly just thin wrappers +around `luaL_ref()`, `luaL_unref()` and `lua_rawgeti()` but they come up +frequently enough that I think these are helpful. + +```C +lua_pushstring(L, "some string"); +int my_string_ref = hs_rstore(L); +// ... +hs_rload(L, my_string_ref); // load the value referenced by my_string_ref +hs_rdel(L, my_string_ref); // done with this reference, remove from the registry table +``` + +Development +----------- +[(Back to top)](#table-of-contents) + +honeysuckle is still very early in development. As the specifics of the build +process and testing become clearer I'll update this section. + +# License +[(Back to top)](#table-of-contents) + + +honeysuckle is licensed under the [Anti-Capitalist Software License]. +Basically: if you're a single person, a co-op, or a nonprofit, feel free to +use this. Otherwise, send me an email. c: + +[Anti-Capitalist Software License]: https://anticapitalist.software |