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

26.1 – C Functions

As a first example, let us see how to implement a simplified version of a function that returns the sine of a given number (a more professional implementation should check whether its argument is a number):

    static int l_sin (lua_State *L) {
      double d = lua_tonumber(L, 1);  /* get argument */
      lua_pushnumber(L, sin(d));  /* push result */
      return 1;  /* number of results */
Any function registered with Lua must have this same prototype, defined as lua_CFunction in lua.h:
    typedef int (*lua_CFunction) (lua_State *L);
From the point of view of C, a C function gets as its single argument the Lua state and returns (in C) an integer with the number of values it is returning (in Lua). Therefore, the function does not need to clear the stack before pushing its results. After it returns, Lua automatically removes whatever is in the stack below the results.

Before we can use this function from Lua, we must register it. We do this magic with lua_pushcfunction: It gets a pointer to a C function and creates a value of type "function" to represent this function inside Lua. A quick-and-dirty way to test l_sin is to put its code directly into the file lua.c and add the following lines right after the call to lua_open:

    lua_pushcfunction(l, l_sin);
    lua_setglobal(l, "mysin");
The first line pushes a value of type function. The second line assigns it to the global variable mysin. After these modifications, you rebuild your Lua executable; then you can use the new function mysin in your Lua programs. In the next section, we will discuss better ways to link new C functions with Lua.

For a more professional sine function, we must check the type of its argument. Here, the auxiliary library helps us. The luaL_checknumber function checks whether a given argument is a number: In case of errors, it throws an informative error message; otherwise, it returns the number. The modification in our function is minimal:

    static int l_sin (lua_State *L) {
      double d = luaL_checknumber(L, 1);
      lua_pushnumber(L, sin(d));
      return 1;  /* number of results */
With the above definition, if you call mysin('a'), you get the message
    bad argument #1 to `mysin' (number expected, got string)
Notice how luaL_checknumber automatically fills the message with the argument number (1), the function name ("mysin"), the expected parameter type ("number"), and the actual parameter type ("string").

As a more complex example, let us write a function that returns the contents of a given directory. Lua does not provide this function in its standard libraries, because ANSI C does not have functions for this job. Here, we will assume that we have a POSIX compliant system. Our function, dir, gets as argument a string with the directory path and returns an array with the directory entries. For instance, a call dir("/home/lua") may return the table {".", "..", "src", "bin", "lib"}. In case of errors, the function returns nil plus a string with the error message.

    #include <dirent.h>
    #include <errno.h>
    static int l_dir (lua_State *L) {
      DIR *dir;
      struct dirent *entry;
      int i;
      const char *path = luaL_checkstring(L, 1);
      /* open directory */
      dir = opendir(path);
      if (dir == NULL) {  /* error opening the directory? */
        lua_pushnil(L);  /* return nil and ... */
        lua_pushstring(L, strerror(errno));  /* error message */
        return 2;  /* number of results */
      /* create result table */
      i = 1;
      while ((entry = readdir(dir)) != NULL) {
        lua_pushnumber(L, i++);  /* push key */
        lua_pushstring(L, entry->d_name);  /* push value */
        lua_settable(L, -3);
      return 1;  /* table is already on top */
The luaL_checkstring function, from the auxiliary library, is the equivalent of luaL_checknumber for strings.

(In extreme conditions, that implementation of l_dir may cause a small memory leak. Three of the Lua functions it calls can fail due to insufficient memory: lua_newtable, lua_pushstring, and lua_settable. If any of these calls fails, it will raise an error and interrupt l_dir, which therefore will not call closedir. As we discussed earlier, on most programs this is not a big problem: If the program runs out of memory, the best it can do is to shut down anyway. Nevertheless, in Chapter 29 we will see an alternative implementation for a directory function that avoids this problem.)