Copyright © 2002 Enrico Colombini. All rights reserved.
This software, including its documentation, is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
Lua is a powerful, flexible and elegant dynamic language, designed and written by Waldemar Celes, Roberto Ierusalimschy and Luiz Henrique de Figueiredo at TeCGraf, PUC-Rio in Brazil.
If you just need to call existing C code from Lua, consider toloa, a very good automated tool from Waldemar Celes: it will save you a lot of work and it will protect you against accidental mistakes.
On the other hand, there may be situations where an automated tool would probably not be the best choice; for example:
Please note that glua is designed to work with Lua 4.0; it may require changes for other versions.
It does not natively handle cross-language access to structures, C++ classes or Lua tables. This reflects my beliefs about interface design: to build reliable large programs, software layers should communicate to each other through as narrow an interface as possible (apparently, this is the opposite of what Microsoft thinks).
Of course all of the above can be done 'by hand' using the appropriate Lua macros: glua macros and lua macros can be freely intermixed (if you know what you are doing).
To use glua, just #include glua.h and link with glua.c.glua.h Header file to #include in your source files. glua.c C file to compile and link with your code. glua.html Documentation (this file). gluatest.c Test suite and examples (C side). gluatest.lua Test suite and examples (Lua side).
To run the gluatest test suite, see Examples and tests.
Glua does not have any special provision for C++ but can be used in mixed C/C++ programs like any other C module.
And here is a Lua interface for the above Half() function, written using glua:double Half(double v) { return v / 2; }
A few notes about the above interface function:glua_function(Half) double v = glua_getNumber(1); /* get Lua argument #1 */ v = Half(v); /* call the C function */ glua_pushNumber(v); /* return one numeric result */ return 1; /* 1 = one Lua result value */ }
(this is standard practice when writing Lua functions in C; glua itself does not require any initialization, but it makes it easier to write the function initialization code).
First, a list of all Lua-accessible functions must be written; so far we have only one such function:
Registering is than typically done for all functions (and other item, as we will see) from a library opening function, such as:static glua_fitem flist[] = { glua_fn(Half), /* declare the Half() function */ //... /* list other functions here */ };
Some notes on the above list and function:void misc_open (lua_State* lua) { glua_regFunctions(flist); /* init functions */ //... /* other library init here */ }
Of course the declaration for the library init function misc_open could be put instead in a small header file, say misc.h.#include "lua.h" void misc_open(lua_State* lua); /* declare library init function */ main(int argc, char *argv[]) { lua_State *lua; lua = lua_open(0); /* open Lua, set default stack */ lua_baselibopen(lua); /* open Lua libraries */ lua_iolibopen(lua); lua_strlibopen(lua); lua_mathlibopen(lua); misc_open(lua); /* call library init function */ lua_dofile(lua, "luacode.lua"); /* execute some Lua code */ lua_close(lua); return 0; }
as usual for declarations of C functions to be called from C++.extern "C" { //...declarations here }
If more than one argument is passed in the call, an error message is issued:glua_function(Half) double v = glua_getNumber(1); /* get Lua argument #1 */ glua_getNone(2); /* there must be no argument #2 */ v = Half(v); glua_pushNumber(v); return 1; }
Note that glua already checks for the presence of the required arguments of the correct type (a valid number, in this case) and issues a meaningful error message if one of those is not found:error: Half(): unexpected arg #2 stack traceback: 1: function `Half' [C] 2: ... [Lua stack trace follows]
Using glua_getNone ensures that no extra arguments are passed to the function.error: Half(): arg #1 must be a valid number stack traceback: 1: function `Bitand' [C] 2: ... [Lua stack trace follows]
This function must be registered, as we did with the Half function, by adding it to the function list used by the library initialization function:glua_function(ToPolar) double x = glua_getNumber(1); /* get Lua argument #1 */ double y = glua_getNumber(2); /* get Lua argument #2 */ double r; double a; glua_getNone(3); /* there must be no argument #3 */ r = sqrt(x*x + y*y); a = atan2(y, x); glua_pushNumber(r); /* return numeric results */ glua_pushNumber(a); return 2; /* 2 = two Lua result values */ }
It can then be called from Lua as:static glua_fitem flist[] = { glua_fn(Half), /* declare the Half() function */ glua_fn(ToPolar), /* declare the ToPolar() function */ //... /* list other functions here */ };
Conversely, a function requiring no arguments will just check that none is supplied in the call:rho,theta = ToPolar(0.43, -0.27)
and a function returning no results will terminate with:glua_getNone(1)
(as described in the Lua manual).return 0;
To make them visible from the Lua side, their names must be written into a list of available constants:#define MAXDATA 1023 #define CONVERT 1936.27 enum { NO, OK };
And a call to glua_regConstants must be added to the library opening function that, as said above, must be called once before using the library:static glua_citem clist[] = { glua_const(MAXDATA), glua_const(CONVERT), glua_const(NO), glua_const(OK) };
Once again, note that the lua_State* pointer declared as argument to misc_open must be called lua, because that name is used by glua macros (see Hidden data).void misc_open (lua_State* lua) { glua_regFunctions(flist); /* init functions */ glua_regConstants(clist); /* init constants */ //... /* other library init here */ }
String constants are currently not supported by glua, but they can be set using standard Lua macros (see Mixing glua and Lua macros).
Userdata of the same 'type' are labeled with the same tag; on the C side a tag is simply an integer value:
A tag value must be requested to glua during initialization, i.e. in the usual library opening function:typedef struct { /* a C type */ int xsize; int ysize; unsigned char *bits; } Bitmap; int bitmap_tag; /* tag for Bitmap* (pointer to Bitmap) userdata */
The glua_newtag macro is similar to the standard lua_newtag macro but, in addition to requesting a tag value, it also registers a name (an arbitrary string chosen by the programmer), in this case the name Bitmap, that will be used for meaningful error messages.void misc_open (lua_State* lua) { glua_regFunctions(flist); /* init functions */ glua_regConstants(clist); /* init constants */ bitmap_tag = glua_newtag("Bitmap"); /* request a tag*/ //... /* other library init here */ }
(tag values requested with lua_newtag will also work, but in this case glua will not be able to identify the userdata type in error messages and will just show the numeric value of the associated tag).
As usual in glua, for this macro to work the lua_State* pointer declared as argument to misc_open must be called lua, because that name is used by glua macros (see Hidden data).
An userdata value can be returned from a function by pushing it on the Lua stack with glua_pushPointer:
This also fixes a problem with Lua 4.0 concerning the 'nondeterministic' handling of userdata with value 0: a NULL pointer is pushed as Lua nil value, so that it can be easily detected as invalid if used in a call.Bitmap *b = NewBitmap(); /* pointer to a C object of type Bitmap */ glua_pushPointer(cp, bitmap_tag); /* return a "Bitmap" userdata */
To receive an userdata as argument of a function, the macro glua_getUserdata is used:
Glua will issue a meaningful error message if the first argument is not an userdata with an associated "Bitmap" tag:glua_function(GetBitmapInfo) Bitmap *b = glua_getUserdata(1, bitmap_tag); /* arg #1 must be a "Bitmap" userdata */ //... }
Error checking is fast, as the registered name ("Bitmap") will be retrieved only if an error has actually been detected.error: GetBitmapInfo(): arg #1 must be an userdata with tag <Bitmap> stack traceback: 1: function `GetBitmapInfo' [C] 2: ... [Lua stack trace follows]
There is, however, a difference: glua_getNumber will check that the stack position 1 actually contains a valid number, while lua_tonumber will do no such check.double x = glua_getNumber(1); /* get Lua argument #1 */ double x = lua_tonumber(lua, 1); /* get Lua argument #1 */
The first argument of lua_tonumber must be called lua, because that name is used by glua macros (see Hidden data).
Standard Lua macros can be used to increase efficiency by discarding error checking (an unsafe practice) or, more realistically, to do things that glua doesn't do, such as accessing the content of Lua tables, pushing unterminated strings and so on.
(by the way, this ability to mix glua and Lua macros is the main reason why I removed from glua the argument auto-counting that I first implemented: it was useful in simple cases but it could be a nuisance in complex ones. The need to 'manually' indicate the stack position of the desired argument in macros like glua_getNumber(3) can lead to mistakes, but checking this during testing is fairly easy).
will be translated to:glua_function(Half)
The first variable, the parameter lua, is the customary Lua state and is used by most of glua macros; I chose this name instead of the 'canonical' L because I don't like upper case variable names (and the lower case letter l can be confused with the 1 digit).static int glua_fn_Half(lua_State* lua) { static const char *glua_fname = "Half";
(I apologize for not #defining it in glua.h so that it could be changed at will, but when I thought of it it was a bit too late: all testing would have to be redone).
The second variable, glua_fname, is only used to issue meaningful error messages with the name of the function; being statically allocated, it adds no cost to the function call.
The 'user name' associated to an userdata tag by the call to glua_newtag is kept in the Lua registry. For example, this call:
writes into the Lua register:bitmap_tag = glua_newtag("Bitmap"); /* request a tag */
where the 'x' part (whose length depends on the CPU's word size) represents the tag value in hexadecimal string form; this is only used in case of error, to issue a meaningful message. Currently, there is no way to 'unregister' a tag from glua.key: glua_tag_xxxxxxxx value: Bitmap
To run the examples:
void gluatest_open (lua_State* lua);
gluatest_open(lua); lua_dofile(lua, "gluatest.lua");
Sparse samples of my work, mostly from old times, can be found on my pages, in Italian.
If you like glua, write me (disclaimer: I can't guarantee any type of support and I am most definitely not a Lua expert).
Enrico Colombini
glua_function(fname)
Defines a C interface function callable from Lua with name fname. Takes the place of a C function declaration, but must not be followed by the usual opening brace. See example.
void glua_regFunctions(flist)
Registers with Lua the list of interface functions flist. The list must be an array of glua_fitem elements, popolated with glua_fn() calls. See example.
void glua_regConstants(clist)
Registers with Lua the list of numeric constants clist. The list must be an array of glua_citem elements, popolated with glua_const() calls. See example.
int glua_newtag(tagname)
Requests a new tag from Lua and registers tagname for use in error messages regarding userdata values (usually pointers) associated with that tag. See example.
double glua_getNumber(argn)
Reads a numeric value from argument argn; issues an error message if argument argn cannot be interpretes as a valid numeric value. See example.
int glua_getInteger(argn)
Reads the integer part of a numeric value from argument argn; issues an error message if argument argn cannot be interpretes as a valid numeric value. Does not check if the value has a fractionary part. See examples in gluatest.c.
const char *glua_getString(argn)
Reads a pointer to a string from argument argn; issues an error message if argument argn cannot be interpretes as a valid string value. See examples in gluatest.c.
void *glua_getUserdata(argn, tag)
Reads an userdata value (usually a C pointer) associated with tag from argument argn; issues an error message if argument argn cannot be interpretes as a valid userdata value or if its tag is different from tag. See example.
void glua_getNone(argn)
Issues an error message if there is an argument argn in the Lua call. See example.
void glua_pushNumber(double v)
Pushes the numeric value v into the Lua stack. See example.
void glua_pushString(const char *s)
Pushes a pointer to the zero-terminated string s into the Lua stack (a copy of the string will be made). See examples in gluatest.c.
void glua_pushPointer(void *p, int tag)
Pushes the pointer p into the Lua stack as an userdata value associated with tag, or pushes nil if p is NULL. See example.
void glua_pushBoolean(double v)
Pushes the numeric value v into the Lua stack, or pushes nil if v is zero. This translates from a C boolean to a Lua 4.0 boolean, while preserving the numeric value if it is not 'false'.
void glua_pushNil()
Pushes nil into the Lua stack.