The Lua Integration Guide
The Lua Integration Guide
Not everything can be written in Lua. A lot of software, especially libraries, is available only in C, or
C is used to implement some low-level stuff like a binary protocol or direct hardware access.
Multilanguage Development
Programmers have a tendency of favoring a particular programming language and sometimes
defend their choice with almost religious zeal. And then they try to solve every problem in that very
language.
This is not always a good idea. Especially not when different people with different skill levels work
together. Image a senior C programmer with years long of experience and the student who just
started learning to program. Giving the experienced programmer C and the student Lua will make
them both productive and let them collaborate. Multilanguage development bridges the skill and
experience gap.
The art of Lua integration is to make available complex software, written in C, to Lua in a way a
Lua programmer would expect it. Clean and clear syntax, using tables as the only data structure,
automatic memory management, automatic cleaning up of ressources, and, using Lua paradigms.
Lua 5.4 was released in june 2020. This version introduces new concepts to the language and
the C API, like e.g. constant values, to-be-closed values, and, multiple uservalues. These new
additions to the language can be helpful when integrating C code with Lua, so I decided to
base the guide on Lua 5.4. Most concepts, patterns, and, best practices presented here,
however, apply to older versions of Lua as well.
1
Making Software Scriptable
The crucial step to make software that is written in C scriptable with Lua is to integrate the Lua
language into the software written in C.
Lua is a small library that the C program must be linked with. The C program, which we call the
host program from now on, must then create one or more Lua states. A Lua state is an isolated Lua
execution environment which means that if the host program creates more than one Lua state,
these Lua states can not see each other nor can they exchange any data (unless the host program
provides means for such data exchange.)
It is assumed that the Lua library liblua.a resides in the path /usr/local/lua and the Lua header files
in /usr/local/lua/include:
#include <lualib.h> ①
#include <lauxlib.h> ②
② This is the auxiliary Lua header file, it provides macros that usually come in handy then
working with the Lua C library.
Now anywhere in the host program we have to create a Lua state and keep a reference to it. The
function that creates the Lua state returns a pointer to a lua_State variable, which we can store let’s
say in a global variable:
2
lua_State *L;
void
main(int argc, char *argv[])
{
/* Create a Lua state */
L = luaL_newstate(); ①
① luaL_newstate() is actually a macro from lauxlib.h, making it very easy to create a new Lua state.
The lua_newstate() function would require us to pass a memory allocation function.
luaL_openlibs(L);
We are now ready to call some Lua code, e.g. from a file named script.lua:
luaL_dofile(L, "script.lua");
When we are done with our Lua state, we call lua_close() to finish the Lua state. Remind yourself
that Lua is garbage collected language and calling lua_close()will allow it to run the garbage
collector one last time, freeing all resources.
lua_close(L);
We see a pattern here: All functions of the C API, besides the functions that create a new Lua
state — luaL_newstate() and lua_newstate() — expect a lua_State * to be passed as the first
parameter.
3
#include <stdio.h>
#include <lualib.h>
#include <lauxlib.h>
lua_State *L;
void
main(int argc, char *argv[])
{
/* Create a Lua state */
L = luaL_newstate();
return 0;
}
We have seen how to link Lua with a host program, create an empty Lua state, open the standard
libraries, and, executing Lua code.
But this is a rather boring example, since all it does is to run a Lua script in complete isolation from
the host program. There is absolute no interaction between the host program and the Lua script.
This is where the Lua C API enters the stage.
4
The Lua C API
The Lua C API provides a rich and very carefully designed set of functions for a host program to
interact with a Lua script.
Using the Lua C API it is not only possible to create or close a Lua state, open the standard Lua
libraries and execute Lua code from a file, but a lot, lot more.
Index Content
1 "miller"
2 42
3 "south"
4 "north"
5
To return values to Lua, the C function pushes the values to the stack in the order they should be
returned. Consider the following stack and assume the function returns the integer 3, indicating
three result values:
Index Content
1 "west"
2 "east"
3 42
The calling Lua function will receive this values as three return values:
So dir1 contains 'west, dir2 'east, and, media the integer 42.
The Lua C API provides a rich set functions for querying and manipulating the stack. The Lua
auxiliary library provides additional functions which not retrieve values from the stack, but check
for the expected type on go.
The functions for retrieving values from the stack are named lua_totype() while the functions in
the auxiliary library are named luaL_checktype().
To push values to the stack, functions named lua_pushtype() are provided by the Lua C API.
6
Calling Lua Code From C
Lua provides basically two functions to call Lua code from C, lua_call() and lua_pcall(). They
differ in how error situations are handled.
lua_call() is used to call a Lua function in unprotected mode, meaning the host program will
simply be terminated by a call to exit() in the case of an error, e.g. the Lua code calling the error()
function.
lua_pcall()on the other hand calls a Lua function in protected mode, which means it will not
terminate the calling program in case of an error. It will rather signal through its return value that
there has been a problem and the Lua error message will be provided to the host program
conveniently in the first element of the virtual stack. Thus we can call lua_tostring(L, 1) to
retrieve the Lua error message.
To call a Lua function, the Lua virtual stack is again used to pass arguments and retrieve return
values. To call a Lua function we first push onto the stack the function to be called, then the
arguments to be passed to the function. Once the stack is setup, we call either lua_pcall() or
lua_call(), passing the number of arguments be pushed onto the stack and the number of return
values we expect:
As an example, we want to call the print()function with three arguments, "miller", "north", and, the
number 42. The following C code would prepare our stack:
lua_getglobal(L, "print"); ①
lua_pushstring(L, "miller");
lua_pushstring(L, "north");
lua_pushinteger(L, 42);
① lua_getglobal() pushes onto the stack the value of the global passed as argument, in this case
the print() function (remember that in Lua functions are just ordinary values, so they can be put
onto the stack).
Index Content
4 The integer 42
7
lua_call(L, 3, 0);
8
Calling C Code From Lua
For Lua to be able to call C code, the C code must be made available to Lua. In the simplest form, the
host program will create a global variable holding the C function to be called.
Any C function that will be called from Lua must follow this protocol:
The signature of a C function that will be called from Lua looks as follows:
int
myFunction(lua_State *L)
{
}
Once we have written such a function it must be made known to the Lua state. A simple way is to
define a global name for the function.
...
lua_pushcfunction(L, myFunction);
lua_setglobal(L, "myFunction");
...
9
/* The function that will be called from Lua */
static int
greetings(lua_State *L)
{
const char *name;
static int invocations = 1;
...
① We use the auxiliary function luaL_checkstring() here which will ensure that the stack element
1 is actually a string. It will throw an error otherwise.
Once this has been setup, Lua can call the function in the usual way:
print('the greetings functions has been called ' .. invocations .. ' times.')
① If the sole argument to a Lua function is a string, then no parentheses are needed.
10
Userdata: Defining Your Own Data Types
Lua comes with basic data types like numbers, integers, strings, boolean etc. For more complex data
structures it knows exactly one data type, the table.
C code, on the other hand, usually comes with complex data types and structures. As an example
let’s look at libuuid, a C library to generate and deal with universal unique identifiers, UUIDs (this
library will also serve as an example in the chapter Binding Existing Libraries.)
libuuid defines an opaque data type uuid_t, which is used to hold a generated uuid. We have no
idea how uuid_t is composed internally, neither do we need to. What we need is a way to tie a
uuid_t C variable to a Lua value, so that Lua can deal with uuids and pass uuids to other functions.
The Lua C API provides us with userdata for exactly this purpose. A Lua userdata value is a Lua
value that can be passed around just like any Lua value. Internally it is a piece of memory with a
user defined size that we declare when we create the userdata value. Like all Lua values, userdata
values get garbage collected eventually when they are no longer in use, the allocated memory is
then automatically freed.
We create a userdata value by calling the lua_newuserdatauv() function, which returns a pointer to
the allocated memory. As the Lua manual states, our code can freely use this memory:
uuid_generate(uuid); ①
u = lua_newuserdatauv(L, sizeof(uuid_t), 0); ②
uuid_copy(*u, uuid); ③
② Allocate enough memory to hold a variable of the uuid_t type. Ignore the third argument for
now.
In short, userdata is application memory that is managed by Lua, with automatic memory
management for free.
11
char *text;
text = malloc(1024); ①
② We call the Lua print() function with one argument and expect no results.
Remember that Lua uses a longjmp() call when it encounters an error internally? And in fact, all
three functions involved in the example above, lua_getglobal(), lua_pushstring(), and, lua_call()
may raise an error, causing our program to longjmp() to a location that Lua defined using a setjmp()
call earlier.
The longjmp() call will unwind the stack, but it will not free the allocated memory. We have just
created a potential memory leak.
We can, however, leave memory management to the Lua C API and be completely safe, even if any
of the lua_ functions raises an error:
char *text;
② We again call the Lua print() function with one argument and expect no results.
③ Don’t free the allocated memory. Lua will take care of it.
12
Metatables
Values in Lua can be assigned a metatable which defines the behaviour of the value. Metatables are
ordinary Lua tables that contain functions, so-called metamethods, which have predefined names
starting with two underscores.
You can not just invent any name for a metamethod, there is a list of metamethods than can be
defined and in which situation they are called by the Lua core.
13
Metamethod Used for Operator
Once a metatable has been assigned to a value, Lua will call the metamethods whenever needed
under the hood and completely invisible to the Lua program.
Metatables are one of the most powerfull concepts in Lua, especially when combined with
userdata, one can do magic. The concept of metatables underline one strongest paradigm in Lua,
namely to provide mechanisms, not policies.
For example, while Lua itself is not an object-oriented language, it can quite easily be made one by
proper use of metatables.
To get an idea of how powerful metatables are, consider the following scenario: We have a userdata
value that is not the actual data, but merely a pointer to the real data.
In the example that follows, a PostgreSQL result set is returned by a query function. The actual size
of the data is not known, so we have to store a pointer to it. Our userdata value effectively becomes
a pointer to a pointer:
PGresult **res;
What happens if this userdata value is garbage collected? The pointer to the pointer will be freed by
Lua, but not the pointer itself, leading to a memory leak (in PostgreSQL, you have to call
PQfreemem(*res) to free the result set.)
If, however, we define a table with a __gc() function and set this table as the metatable of above
userdata value, then Lua would call the __gc() function just before the value is garbage collected. In
the __gc() function, which receives the to-be-freed value on the virtual stack, we can then pop our
value from the stack and call PQfreemeem(), releasing the memory held by the result set.
14
To-be-closed Variables
As Lua is a garbage collected language, the Lua programmer does not have to care about memory
management at all. Every value, once it is no longer used, will eventually be garbage collected and
the memory it occupied will be be freed. This is also true for values that have been created by C
code as userdata values.
While garbage collection is a great concept from the Lua programmers point of view, it is not
optimal from the view of a C programmer who writes a Lua module in C. There is no control over
when a value actually gets garbage collected. This can lead to situations where a lot of no longer
used — and no longer accessible — memory is still being held by the process running the Lua
interpreter.
As an example, imagine a PostgreSQL database interface being used in a Lua program that runs
thousands of SQL queries per second. Each query returns a PostgreSQL result set that is essentially
allocated memory that has to be explicitely freed by a call to the PQfree() C function. Whe could
free the memory with an explicit call from the Lua program, but a Lua programmer might forget to
call the free function, assuming everything is garbage collected.
On the other hand, if we free the memory at garbage collection time only, we have exactly the
situation where potentially a lot of no longer used memory remains allocated.
Database result sets are only one example, we can think of a lot of other resources that are release
to late or later than needed.
To address this problem, Lua 5.4 introduced to-be-closed variables, a mechanism to free memory or
otherwise release resources at the very moment the variable goes out of scope.
The memory used by the variable res will only be freed at garbage collection time (whenever that
will be.)
If, however, res is annotated as to-be-closed using the new keyword <close>, the underlying
memory can be freed in the __close metamethod, which gets called as soon a the variable goes out
of scope, i.e. when the getName() function returns:
15
local function getName(db)
local res <close> = db:exec('select name from account') ①
return res[1].name
end
If you try to annotate a variable as to-be-closed when the underlying userdata has no __close
metamethod, Lua will throw an error.
For the curious, this is the C function that is called in the Lua PostgreSQL interface to free memory
either when __close is called or when the garbage collector runs:
static int
res_clear(lua_State *L)
{
PGresult **r;
r = luaL_checkudata(L, 1, RES_METATABLE);
if (*r) { ①
PQclear(*r);
*r = NULL;
}
return 0;
}
① Prevent double free of the memory as this function can be called more than one time.
16
Binding Existing Libraries
When binding an existing library, you make its functionality available to Lua. And there is an awful
lot of libraries out there that provide functionality of all sorts and that usually have seen the proof
of time and are well maintained.
Thanks to the well designed Lua C API this process is not very hard. A bit of planning ahead is
nevertheless needed. C libraries are designed with the C programmer in mind, using C
programming paradigms. In Lua things are quite different, e.g.:
• In C we can define complex data structures and our own complex types. Lua has only tables as
data structures.
• In C we must carefully manage memory. Lua has automatic garbage collection and to-be-closed
variables.
Next you must think about how you would like to use the libraries functionality in Lua. I wrote to
use the libraries functionality on purpose, and not provide the libraries functions to Lua
because that’s what designing good Lua bindings is all about: Build a bridge between the Lua and
the C world.
Of course you could just write a binding that is a one-to-one mapping of the C functions to
corresponding Lua functions, but with this approach you’ll end up with a Lua binding that is non-
intuitive to use in many cases.
The libyaml library serves us as an example for a design decision. libyaml is used to parse YAML
data in a C program. It works in a way where the C program repeatetly calls a function which
returns an event. Such an event can be that a data element has been found in the YAML stream, or
that the start of an array has been detected etc. The events itself are not important here, but the fact
that libyaml works by returning a stream of events is.
We must think about what should be achieved with a libyaml Lua binding. YAML describes data in
an easy to read, easy to write text format. In the end, we probably want all that data to be available
in a Lua table. Converting the YAML data into a (probably nested) table seems like a reasonable
design:
Clearly, the approach of simply exposing the event-returning function to Lua would not work well,
17
it would mean that we have to do a lot of overhead work on the Lua side. A better approach is to do
all the processing in C, populating a table while the events are processed. This means more C code
(in fact a lot more) than if we just exposed the event-returning function, but it leads to a very
straightforward usage in Lua.
If you are interested in the full code of luayaml, you may fetch it from Github at https://github.com/
arcapos/luayaml.
The purpose of the Lua UUID binding is to create and parse UUIDs, compare them against each
other or the UUID null value. Let’s first have a look at the uuid test program testuuid.lua to show its
usage:
print 'test_2'
test_2()
In this binding we use Lua userdata to store a pointer to a uuid_t, the internal C representation of a
UUID. We define a metatable name in the headerfile luauuid.h:
#ifndef __LUAUUID_H__
#define __LUAUUID_H__
#define UUID_STR_SIZE 36
#define UUID_METATABLE "uuid"
#endif /* __LUAUUID_H__ */
18
When a uuid is created using one of the libuuid generator functions, teh code will actually create a
new userdata value, store the uuid in it and set the metatable of the new value to the
UUID_METATABLE. As libuuid offers different uuid-generating functions, helper functions are used
that are called by Lua and which hand the actual generator function to the lua_uuid_generator()
function:
static int
lua_uuid_generator(lua_State *L, void (*generator)(uuid_t)) ①
{
uuid_t uuid, *u;
const char *format;
char str[UUID_STR_SIZE + 1];
generator(uuid);
format = lua_tostring(L, 1);
static int
lua_uuid_generate(lua_State *L)
{
return lua_uuid_generator(L, uuid_generate);
}
static int
lua_uuid_generate_random(lua_State *L)
{
return lua_uuid_generator(L, uuid_generate_random);
}
static int
lua_uuid_generate_time(lua_State *L)
{
return lua_uuid_generator(L, uuid_generate_time);
}
② A UUID in text form has been requested, there is no need to store it, instead the string
representation is returned.
19
The latter three functions will be exposed to Lua in luaopen_uuid():
int
luaopen_uuid(lua_State *L)
{
struct luaL_Reg luauuid[] = {
{ "generate", lua_uuid_generate },
{ "generate_random", lua_uuid_generate_random },
{ "generate_time", lua_uuid_generate_time },
/* more functions to come */
{ NULL, NULL }
};
luaL_newlib(L, luauuid);
return 1;
}
The more interesting part is the uuid metatable which defines all the functions and metamethods
we can call on a uuid value. It is also defined in luaopen_uuid():
20
struct luaL_Reg uuid_methods[] = {
{ "clear", lua_uuid_clear },
{ "compare", lua_uuid_compare },
{ "data", lua_uuid_data },
{ "is_null", lua_uuid_is_null },
{ "time", lua_uuid_time },
{ "unparse", lua_uuid_unparse },
{ "__eq", lua_uuid_equal },
{ "__lt", lua_uuid_less },
{ "__le", lua_uuid_less_or_equal },
{ "__gc", lua_uuid_clear },
{ "__close", lua_uuid_clear },
{ "__tostring", lua_uuid_unparse },
{ "__concat", lua_uuid_concat },
{ "__len", lua_uuid_length },
{ NULL, NULL }
};
if (luaL_newmetatable(L, UUID_METATABLE)) {
luaL_setfuncs(L, uuid_methods, 0);
lua_pushliteral(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3);
lua_pushliteral(L, "__metatable");
lua_pushliteral(L, "must not access this metatable");
lua_settable(L, -3);
}
lua_pop(L, 1);
As an example of how we access the userdata value, let’s look at the implementation of the
unparse() function:
static int
lua_uuid_unparse(lua_State *L)
{
char str[UUID_STR_SIZE + 1];
uuid_t *u;
u = luaL_checkudata(L, 1, UUID_METATABLE);
uuid_unparse(*u, str);
lua_pushstring(L, str);
return 1;
}
The remaining functions are no magic either, they just call different functions of the libuuid library
after they retrieved the uuid_t * pointer. The full source code of luauuid can be fetched from
Github: https://github.com/arcapos/luauuid
21
With this explanations and examples you should now be able to create your own bindings. But
before doing so, it is well worth checking if a binding for the library you have in mind doesn’t
already exist. You might be surprised how many different implementations e.g. of decoders for
JSON you will find…
22
Lua Readers
To load Lua code into a Lua state, you will most likely load it from a file or string using either the
luaL_loadfile() or luaL_loadstring() function from the Lua auxiliary library.
Lua itself, however, uses a different approach to load Lua code: It repeatetly calls a function to
return the code piece by piece. This function is called a Lua reader and it can either return the next
piece of code plus its size in bytes or signal that the end of the Lua code has been reached.
So in order to load Lua code using only functions from the core library, you use the lua_load()
function, supplying it with a Lua reader:
int
lua_load(lua_State *L,
lua_Reader reader, ①
void *data, ②
const char *chunkname,
const char *mode);
② The data pointer will be handed to the reader function on each call. It is not used by Lua.
Please note that lua_load() only loads the Lua code, but does not run it. After lua_load()
successfully returns (with return code LUA_OK) the loaded Lua code will be on top of the stack.
But how does the Lua reader function look like and how is it called? The function returns the next
piece of Lua code as a const char * pointer and gets the Lua state, the data pointer and a pointer to
a size_t as arguments:
const char *
myReader(lua_State *L, void *data, size_t size)
{
/* Return a piece of Lua source and put its size in size */
}
When there is no more Lua code to be returned, the reader function returns either NULL or sets
size to zero.
The functions found in the Lua auxiliary library to load Lua code are in fact unsurprisingly
implemented as Lua readers.
What makes this approach interesting? It allows us to supply a function that returns Lua code from
any source, e.g. a network connection, a HTTP request, an object stored in a database, or, even
synthesized Lua code that is built on the fly from parsing a different code format.
23
Lua Templates use a Lua reader to process source templates
The Lua templates engine, used to intermix any source language with Lua expressions and
Lua code, uses a Lua reader to parse a source file and convert it to Lua code. This happens
only when a template is rendered for the first fime. The code will be compiled to bytecode
and on subsequent calls of the same template, the Lua code is directly executed withouth the
need for parsing or compiling it again. The Lua code produced by the reader function will
output the template content and at the same time run the Lua code fragments that were
present in the original template.
Let’s assume that we have a testzip.zip file that contains an entry testzip.lua with the code we want
to load:
We first define how we want our helper function to look like, i.e. the function which we call to load
Lua from a .zip file. This means, we design a function similar to luaL_loadfile() and
`luaL_loadstring().
One approach is to pass the path to the .zip file and the path to the Lua file contained within the .zip
file to the function:
Before we look at the implementation of lua_loadzip(), lets write a small command line tool which
hosts the Lua environment, loads and calls the Lua code contained in a .zip file. We call the utility
ziplua and it is called with two arguments, the path to the .zip file and the path to the Lua code.
% ./ziplua
usage: ziplua <zipfile> <path>
% ./ziplua testzip.zip testzip.lua # Load and run testzip.lua
%
24
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
int
main(int argc, char *argv[])
{
lua_State *L;
if (argc != 3) {
fprintf(stderr, "usage: ziplua <zipfile> <path>\n");
exit(1);
}
L = luaL_newstate();
if (L == NULL) {
fprintf(stderr, "memory error\n");
exit(1);
}
luaL_openlibs(L);
25
fprintf(stderr, "error running message handler: %s\n",
lua_tostring(L, -1));
exit(1);
case LUA_OK:
;
}
lua_close(L);
return 0;
}
With that in place, let’s develop the corresponding Lua reader and the lua_loadzip() function. For
the actual processing of .zip files we will rely on the libzip library from https://libzip.org.
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <zip.h>
We will need some state information for the actual reader function, which will be passed in the
data * pointer. In our case we will need a pointer to the zip file from which we read plus the
remaining size which we still have to read. We define a zip_reader_stat_t type to keep this
information.
typedef struct {
zip_file_t *zf; ①
size_t size;
} zip_reader_stat_t;
zip_reader_stat_t st;
① path contains the path to the Lua file within the .zip file.
lua_load() will now call our zip_Reader() function, which will try to read up to st.size bytes from
the .zip file and return them to lua_load. As reading can return fewer bytes than requested, it will
26
also return the number of bytes actually read and decrement st.size by that number. Once st.size
is zero, the function will return NULL, thus terminating the loading process.
The complete function with the zip_Reader() function now looks like this:
#include <stdlib.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <zip.h>
typedef struct {
zip_file_t *zf;
size_t size;
} zip_reader_stat_t;
free(buf);
if (st->size == 0)
return NULL;
buf = malloc(st->size);
*size = zip_fread(st->zf, buf, st->size);
st->size -= *size;
return buf;
}
int
lua_loadzip(lua_State *L, const char *zipfile, const char *path)
{
zip_t *zip;
zip_stat_t sb;
zip_reader_stat_t st;
int error;
if (zip == NULL) {
switch (error) {
case ZIP_ER_INVAL:
lua_pushstring(L, "invalid path");
break;
27
case ZIP_ER_MEMORY:
lua_pushstring(L, "memory error");
break;
case ZIP_ER_NOENT:
lua_pushstring(L, "file not found");
break;
case ZIP_ER_NOZIP:
lua_pushstring(L, "not a zip file");
break;
case ZIP_ER_OPEN:
lua_pushstring(L, "file open error");
break;
case ZIP_ER_READ:
lua_pushstring(L, "read error");
break;
default:
lua_pushstring(L, "unknown zipfile related error");
}
return LUA_ERRFILE;
}
if (zip_stat(zip, path, 0, &sb)) {
lua_pushstring(L, "can't stat zipfile entry");
zip_close(zip);
return LUA_ERRFILE;
}
zip_fclose(st.zf);
zip_close(zip);
return error;
}
28
Useful Helper Functions
lua_vpncall()
The lua_vnpcall()function calls a Lua function by name, specifying parameters and return values
in a printf() like manner.
Parameters passed as variable arguments and the expected results must be indicated by strings in
arg and ret containing the following characters:
b int Lua
f double Number
d int Integer
l long Integer
s char * String
To pass a string and number to a function called test, expecting an int to be returned, one would
call the function as follows:
int rv;
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <lua.h>
#include <lualib.h>
int
lua_vnpcall(lua_State *L, char *table, char *func, char *arg, char *ret, ...)
{
va_list ap;
int n, retval, args, rets, pop;
29
char *types, *t, *fnam, *f;
fnam = strdup(func);
if (fnam == NULL) {
lua_pushstring(L, strerror(errno));
return LUA_ERRMEM;
}
pop = 0;
if (table != NULL) {
lua_getfield(L, -1, table);
if (lua_isnil(L, -1)) {
lua_pushstring(L, "no such table");
lua_pop(L, 1);
return LUA_ERRRUN;
}
pop++;
}
f = fnam;
while ((t = strsep(&f, ".")) != NULL) {
lua_getfield(L, -1, t);
if (lua_isnil(L, -1)) {
free(fnam);
lua_pushstring(L, "no such function");
if (pop)
lua_pop(L, pop);
return LUA_ERRRUN;
}
pop++;
}
free(fnam);
va_start(ap, ret);
args = 0;
if (arg != NULL) {
for (types = arg; *types; types++)
switch (*types) {
case 'b':
lua_pushboolean(L, va_arg(ap, int));
args++;
break;
case 'f':
lua_pushnumber(L, va_arg(ap, double));
args++;
break;
case 'd':
lua_pushinteger(L, va_arg(ap, int));
args++;
break;
case 'l':
30
lua_pushinteger(L, va_arg(ap, long));
args++;
break;
case 'L':
lua_pushinteger(L,
va_arg(ap, long long));
args++;
break;
case 's':
lua_pushstring(L, va_arg(ap, char *));
args++;
break;
default:
lua_pop(L, 1 + args + pop);
lua_pushstring(L, "unknown return type");
va_end(ap);
return LUA_ERRRUN;
}
}
rets = ret != NULL ? strlen(ret) : 0;
if ((retval = lua_pcall(L, args, rets, 0))) {
va_end(ap);
if (pop)
lua_pop(L, pop);
return retval;
}
if (ret != NULL) {
for (n = rets, types = ret; *types; n--, types++)
switch (*types) {
case 'b':
*(va_arg(ap, int *)) =
lua_toboolean(L, -n);
break;
case 'f':
*(va_arg(ap, double *)) =
lua_tonumber(L, -n);
break;
case 'd':
*(va_arg(ap, int *)) =
lua_tointeger(L, -n);
break;
case 'l':
*(va_arg(ap, long *)) =
(long)lua_tointeger(L, -n);
break;
case 'L':
*(va_arg(ap, long long *)) =
(long long)lua_tointeger(L, -n);
break;
case 's':
31
*(va_arg(ap, char **)) =
(char *)lua_tostring(L, -n);
break;
default:
lua_pop(L, lua_gettop(L));
lua_pushstring(L, "unknown return type");
va_end(ap);
return LUA_ERRRUN;
}
if (rets)
lua_pop(L, rets);
}
va_end(ap);
if (pop)
lua_pop(L, pop);
return 0;
}
lua_vpcall()
The lua_vpcall() function is similar to lua_vnpcall(), but instead of passing a function name, it
expects the function to be on top of the Lua stack.
#include <stdarg.h>
#include <string.h>
#include <lua.h>
#include <lualib.h>
int
lua_vpcall(lua_State *L, char *arg, char *ret, ...)
{
va_list ap;
int n, retval, args, rets;
char *types;
va_start(ap, ret);
args = 0;
if (arg != NULL) {
for (types = arg; *types; types++)
switch (*types) {
case 'b':
lua_pushboolean(L, va_arg(ap, int));
args++;
break;
case 'f':
lua_pushnumber(L, va_arg(ap, double));
32
args++;
break;
case 'd':
lua_pushinteger(L, va_arg(ap, int));
args++;
break;
case 'l':
lua_pushinteger(L, va_arg(ap, long));
args++;
break;
case 'L':
lua_pushinteger(L,
va_arg(ap, long long));
args++;
break;
case 's':
lua_pushstring(L, va_arg(ap, char *));
args++;
break;
default:
lua_pop(L, 1 + args);
lua_pushstring(L, "unknown parameter type");
va_end(ap);
return LUA_ERRRUN;
}
}
rets = ret != NULL ? strlen(ret) : 0;
if ((retval = lua_pcall(L, args, rets, 0))) {
va_end(ap);
return retval;
}
if (ret != NULL) {
for (n = rets, types = ret; *types; n--, types++)
switch (*types) {
case 'b':
*(va_arg(ap, int *)) =
lua_toboolean(L, -n);
break;
case 'f':
*(va_arg(ap, double *)) =
lua_tonumber(L, -n);
break;
case 'd':
*(va_arg(ap, int *)) =
lua_tointeger(L, -n);
break;
case 'l':
*(va_arg(ap, long *)) =
(long)lua_tointeger(L, -n);
break;
case 'L':
33
*(va_arg(ap, long long *)) =
(long long)lua_tointeger(L, -n);
break;
case 's':
*(va_arg(ap, char **)) =
(char *)lua_tostring(L, -n);
break;
default:
lua_pop(L, lua_gettop(L));
lua_pushstring(L, "unknown return type");
va_end(ap);
return LUA_ERRRUN;
}
if (rets)
lua_pop(L, rets);
}
va_end(ap);
return 0;
}
34