This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The third edition targets Lua 5.2 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.


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.