Glua

A tool for hand-crafted Lua-C interfaces for Lua 4.0
 
v 1.0 - January 2002 - © Enrico Colombini
 


Glua license

Glua: Lua-C interface glue - v 1.0

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:

  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

What is glua?

Glua is a set of macros and functions designed to help a C programmer write Lua-C interface functions by hand, while retaining error control and high efficiency. Its name means "Lua-C glue".

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:

In these cases, glua could be useful: read on.

Please note that glua is designed to work with Lua 4.0; it may require changes for other versions.
 

What glua is not

Glua is a minimalist tool: it is designed to work with plain ANSI C, though it can be used in mixed C/C++ programs, and it only handles basic Lua data types: numeric constants, numbers, strings, pointers (userdata).

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).
 

Glua files and usage

The glua distribution contains the following files:
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 use glua, just #include glua.h and link with glua.c.

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.
 

A simple function example

Let's start with a very simple case. Here is a C function that halves a floating-point value:
double Half(double v)
{
  return v / 2;
}
And here is a Lua interface for the above Half() function, written using glua:
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 */
}
A few notes about the above interface function: The interface function is complete, but it needs some...
 

Initialization

Defining the function is not enough: it must also be registered, so that it could be called from Lua; this is usually done during initialization, or 'library opening'.

(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:

static glua_fitem flist[] = {
  glua_fn(Half),              /* declare the Half() function */
  //...                       /* list other functions here */
};
Registering is than typically done for all functions (and other item, as we will see) from a library opening function, such as:
void misc_open (lua_State* lua)
{
  glua_regFunctions(flist);   /* init functions */
  //...                       /* other library init here */
}
Some notes on the above list and function: To use this library, currently containing only the function Half, the initialization function (misc_open in the example) must be called once from C, after starting Lua, as for the standard Lua libraries:
#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;
}
Of course the declaration for the library init function misc_open could be put instead in a small header file, say misc.h.
If the initialization function is called from C++, its declaration (and the #include lua.h) should be bracketed with:
extern "C" { 
  //...declarations here
}
as usual for declarations of C functions to be called from C++.
 

Checking for extra arguments

It is a good idea to check that the function doesn't get called with more arguments than expected; one more line will do the trick:
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;
}
If more than one argument is passed in the call, an error message is issued:
error: Half(): unexpected arg #2
stack traceback:
   1:  function `Half' [C]
   2:  ... [Lua stack trace follows]
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(): arg #1 must be a valid number
stack traceback:
   1:  function `Bitand' [C]
   2:  ... [Lua stack trace follows]
Using glua_getNone ensures that no extra arguments are passed to the function.
 

Multiple arguments, multiple results

Designing a Lua function that accepts multiple arguments and/or returns multiple results is straightforward; for example, this function converts from cartesian to polar coordinates:
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 */
}
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:
static glua_fitem flist[] = {
  glua_fn(Half),              /* declare the Half() function */
  glua_fn(ToPolar),           /* declare the ToPolar() function */
  //...                       /* list other functions here */
};
It can then be called from Lua as:
rho,theta = ToPolar(0.43, -0.27)
Conversely, a function requiring no arguments will just check that none is supplied in the call:
glua_getNone(1)
and a function returning no results will terminate with:
return 0;
(as described in the Lua manual).
 

Defining Lua constants

Suppose the following C constants to be defined:
#define MAXDATA  1023
#define CONVERT  1936.27

enum { NO, OK };
To make them visible from the Lua side, their names must be written into a list of available constants:
static glua_citem clist[] = {
  glua_const(MAXDATA),
  glua_const(CONVERT),
  glua_const(NO),
  glua_const(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:
void misc_open (lua_State* lua)
{
  glua_regFunctions(flist);   /* init functions */
  glua_regConstants(clist);   /* init constants */
  //...                       /* other library init here */
}
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).

String constants are currently not supported by glua, but they can be set using standard Lua macros (see Mixing glua and Lua macros).
 

Userdata values

Userdata values are usually employed to safely pass C pointers around in Lua; each userdata has an associated tag to avoid mixing different user types (e.g. different types of pointers).

Userdata of the same 'type' are labeled with the same tag; on the C side a tag is simply an integer value:

typedef struct {         /* a C type */
  int xsize;
  int ysize;
  unsigned char *bits;
} Bitmap;

int bitmap_tag;          /* tag for Bitmap* (pointer to Bitmap) userdata */
A tag value must be requested to glua during initialization, i.e. in the usual library opening function:
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 */
}
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.

(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:

Bitmap *b = NewBitmap();                 /* pointer to a C object of type Bitmap */
glua_pushPointer(cp, bitmap_tag);        /* return a "Bitmap" userdata */
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.

To receive an userdata as argument of a function, the macro glua_getUserdata is used:

glua_function(GetBitmapInfo)
  Bitmap *b = glua_getUserdata(1, bitmap_tag);  /* arg #1 must be a "Bitmap" userdata */
  //...
}
Glua will issue a meaningful error message if the first argument is not an userdata with an associated "Bitmap" tag:
error: GetBitmapInfo(): arg #1 must be an userdata with tag <Bitmap>
stack traceback:
   1:  function `GetBitmapInfo' [C]
   2:  ... [Lua stack trace follows]
Error checking is fast, as the registered name ("Bitmap") will be retrieved only if an error has actually been detected.
 

Mixing glua and Lua macros

Standard Lua macros can be freely intermixed with glua macros; for exemple, these two lines are (almost) equivalent:
double x = glua_getNumber(1);       /* get Lua argument #1 */

double x = lua_tonumber(lua, 1);    /* get Lua argument #1 */
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.

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).
 

Hidden data and glua internals

The glua_function macro declares two hidden variables; in fact, a call such as:
glua_function(Half)
will be translated to:
static int glua_fn_Half(lua_State* lua) 
{
  static const char *glua_fname = "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).

(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:

bitmap_tag = glua_newtag("Bitmap");  /* request a tag */  
writes into the Lua register:
key:   glua_tag_xxxxxxxx
value: Bitmap
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.
 

Examples and tests

The files gluatest.c and gluatest.lua contain a number of examples illustrating how to use glua; they also serve as basic tests for glua.

To run the examples:


About the author

I am a former electronics designer that liked the Apple II a lot. After spending a couple of decades writing introductory courses about computers, programming and electronics, I am currently working as a free-lance consultant.

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 reference



Defining and registering

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.

Getting arguments from the Lua stack

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.

Pushing arguments into the Lua stack

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.

Notes



 Glua documentation - Copyright © 2002 Enrico Colombini - see license