14 апреля 2011

Функция Lua из функции Си из скрипта Lua

Это небольшой совет о том как можно сделать callback вызов lua функции из C. Это довольно просто, правда только когда данная callback-функция единственный аргумент C функции, в иных случаях все немного сложнее, правда только немного.

Нам понадобятся две такие функции как luaL_ref и luaL_unref. Давайте лучше на примере? Каким бы не был ответ, давайте на примере.

#if 0
gcc -o call -g -O0 -llua -lm $0 ; exit
#endif
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

int
cfunc(lua_State *lua)
{
  int function_1;
  int function_2;

  // Вынимаем из стека вторую функцию и запоминаем ее.
  function_2 = luaL_ref(lua, LUA_REGISTRYINDEX);
  // Вынимаем из стека первую функцию и запоминаем ее тоже.
  function_1 = luaL_ref(lua, LUA_REGISTRYINDEX);

  // Вспоминаем про первую функцию (кладем ее в стек)
  lua_rawgeti(lua, LUA_REGISTRYINDEX, function_1);
  // Кладем ее первый аргумент (5)
  lua_pushnumber(lua, 5);
  // Вызываем
  lua_call(lua, 1, 0);

  // Аналогично поступаем и со второй
  lua_rawgeti(lua, LUA_REGISTRYINDEX, function_2);
  lua_pushnumber(lua, 10);
  lua_call(lua, 1, 0);

  // Забываем функции
  luaL_unref(lua, LUA_REGISTRYINDEX, function_1);
  luaL_unref(lua, LUA_REGISTRYINDEX, function_2);

  return 0;
}

int
main(int argc, char *argv[])
{
  const char *str;
  lua_State *lua = luaL_newstate();
  if (!lua)
    {
      fprintf(stderr,
              "%s (%s : %d)\n",
              strerror(errno), __FILE__, __LINE__);
      exit(EXIT_FAILURE);
    }
  lua_pushcfunction(lua, luaopen_base);
  lua_call(lua, 0, 0);
  lua_pushcfunction(lua, cfunc);
  lua_setglobal(lua, "cfunc");
  if (luaL_dofile(lua, "simple.lua"))
    {
      str = lua_tostring(lua, 1);
      fprintf(stderr,
              "%s (%s : %d)\n",
              str, __FILE__, __LINE__);
      exit(EXIT_FAILURE);
    }
  lua_close(lua);
  return 0;
}

А вот так будет выглядеть тестовый скрипт simple.lua.

function foo(moo)
   print(moo)
end

function boo(moo)
   print(moo)
end

cfunc(foo, boo)

Вроде и просто, но сделать вот так вот сразу у меня не получилось, пришлось перелистать документацию по lua.