Friday, January 8, 2010

Extending your Application













Programming in Lua
Part IV. The C API
            
Chapter 25. Extending your Application



25 - Extending your Application





An important use of Lua is as a configuration language.
In this chapter, we will illustrate how we can use Lua to
configure a program,
starting with a simple example and evolving
it to perform more complex tasks.

As our first task,
let us imagine a simple configuration scenario:
Your C program (let us call it pp) has a window
and you want the user to be able to specify the
initial window size.
Clearly, for such simple tasks,
there are several options simpler than using Lua,
such as environment variables or files with name-value pairs.
But even using a simple text file,
you have to parse it somehow;
so, you decide to use a Lua configuration file
(that is, a plain text file that happens to be a Lua program).
In its simplest form,
this file can contain something like the next lines:


-- configuration file for program `pp'
-- define window size
width = 200
height = 300


Now, you must use the Lua API to direct Lua to parse this file,
and then to get the values of the global variables width
and height.
The following function does the job:


#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

void load (char *filename, int *width, int *height) {
lua_State *L = lua_open();
luaopen_base(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);

if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
error(L, "cannot run configuration file: %s",
lua_tostring(L, -1));

lua_getglobal(L, "width");
lua_getglobal(L, "height");
if (!lua_isnumber(L, -2))
error(L, "`width' should be a number\n");
if (!lua_isnumber(L, -1))
error(L, "`height' should be a number\n");
*width = (int)lua_tonumber(L, -2);
*height = (int)lua_tonumber(L, -1);

lua_close(L);
}

First, it opens the Lua package and loads the standard libraries
(they are optional, but usually it is a good idea to have them around).
Then, it uses luaL_loadfile to load the chunk from file filename
and calls lua_pcall to run it.
In case of errors in any of these functions
(e.g., a syntax error in your configuration file),
the call returns a non-zero error code
and pushes the error message onto the stack.
As usual, our program uses lua_tostring with index -1 to get
the message from the top of the stack.
(We defined the error function in Section 24.1.)

After running the chunk,
the program needs to get the values of the
global variables.
For that,
it calls twice lua_getglobal,
whose single parameter (besides the omnipresent lua_State)
is the variable name.
Each call pushes the corresponding global value onto the top of the stack,
so that the width will be at index -2
and the height at index -1 (at the top).
(Because the stack was previously empty,
you could also index from the bottom,
using 1 from the first value and 2 from the second.
By indexing from the top, however,
your code would work even if the stack
was not empty.)
Next, our example uses lua_isnumber to check whether
each value is numeric.
It then uses lua_tonumber to
convert such values to double
and C does the coercion to int.
Finally, it closes the Lua state and returns.

Is it worth using Lua?
As I said before, for such simple tasks,
a simple file with only two numbers in it would be much
easier to use than Lua.
Even so, the use of Lua brings some advantages.
First, Lua handles all syntax details (and errors) for you;
your configuration file can even have comments!
Second, the user is already able to do more complex configurations
with it.
For instance,
the script may prompt the user for some information,
or it can query an environment variable
to choose a proper size:


-- configuration file for program `pp'
if getenv("DISPLAY") == ":0.0" then
width = 300; height = 300
else
width = 200; height = 200
end

Even in such simple configuration scenarios,
it is hard to anticipate what users will want;
but as long as the script defines the two variables,
your C application works without changes.

A final reason for using Lua is that
now it is easy to add new
configuration facilities to your program;
this easiness creates an attitude
that results in programs that are more flexible.










Programming in Lua



No comments: