2010-09-25 16:03:48 +02:00
|
|
|
/*
|
|
|
|
* ld-lua.c
|
|
|
|
*
|
|
|
|
* This file is a part of logdiag.
|
|
|
|
* Copyright Přemysl Janouch 2010. All rights reserved.
|
|
|
|
*
|
|
|
|
* See the file LICENSE for licensing information.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <lua.h>
|
|
|
|
#include <lualib.h>
|
|
|
|
#include <lauxlib.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2010-09-25 16:14:09 +02:00
|
|
|
#include "ld-library.h"
|
2010-09-25 16:55:07 +02:00
|
|
|
#include "ld-symbol-category.h"
|
2010-09-25 21:00:24 +02:00
|
|
|
#include "ld-symbol.h"
|
2010-09-25 16:03:48 +02:00
|
|
|
#include "ld-lua.h"
|
|
|
|
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
/**
|
|
|
|
* SECTION:ld-lua
|
|
|
|
* @short_description: Lua symbol engine.
|
|
|
|
* @see_also: #LdSymbol
|
|
|
|
*
|
|
|
|
* #LdLua is a symbol engine that uses Lua scripts to manage symbols.
|
|
|
|
*/
|
2010-09-25 16:03:48 +02:00
|
|
|
/* How does the application call the function for rendering?
|
|
|
|
* logdiag.symbols -- readonly table (from lua) -- this can be probably
|
|
|
|
* accomplished using a custom metatable that errors out on newindex,
|
|
|
|
* items will be added to this table only in C.
|
2010-09-25 21:00:24 +02:00
|
|
|
* It can also be placed into the Lua registry.
|
2010-09-25 16:03:48 +02:00
|
|
|
* logdiag.symbols[ident].render(cr) -- here "ident" is the full path
|
|
|
|
* to this symbol
|
|
|
|
* logdiag.symbols[ident].names[lang, area, terminals] -- these
|
|
|
|
* subarrays need not be in this array
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
/*
|
|
|
|
* LdLuaPrivate:
|
|
|
|
* @L: Lua state.
|
|
|
|
*
|
|
|
|
* The library contains the real function for rendering.
|
|
|
|
*/
|
|
|
|
struct _LdLuaPrivate
|
|
|
|
{
|
|
|
|
lua_State *L;
|
|
|
|
};
|
2010-09-25 16:03:48 +02:00
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
G_DEFINE_TYPE (LdLua, ld_lua, G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
static void ld_lua_finalize (GObject *gobject);
|
|
|
|
|
|
|
|
static void *ld_lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize);
|
2010-09-25 16:03:48 +02:00
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
|
2010-09-25 21:00:24 +02:00
|
|
|
/*
|
|
|
|
* LdLuaData:
|
|
|
|
* @self: A reference to self.
|
|
|
|
* @category: A reference to parent category of the currently processed file.
|
|
|
|
*
|
|
|
|
* Full user data to be stored in Lua registry.
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
LdLua *self;
|
|
|
|
LdSymbolCategory *category;
|
|
|
|
}
|
|
|
|
LdLuaData;
|
|
|
|
|
|
|
|
#define LD_LUA_LIBRARY_NAME "logdiag"
|
|
|
|
#define LD_LUA_DATA_INDEX LD_LUA_LIBRARY_NAME "_data"
|
|
|
|
|
|
|
|
#define LD_LUA_RETRIEVE_DATA(L) \
|
|
|
|
( \
|
|
|
|
lua_pushliteral ((L), LD_LUA_DATA_INDEX), \
|
|
|
|
lua_gettable ((L), LUA_REGISTRYINDEX), \
|
|
|
|
lua_touserdata ((L), -1) \
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
static int ld_lua_logdiag_register (lua_State *L);
|
2010-09-25 16:03:48 +02:00
|
|
|
|
|
|
|
static luaL_Reg ld_lua_logdiag_lib[] =
|
|
|
|
{
|
|
|
|
{"register", ld_lua_logdiag_register},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
static int ld_lua_cairo_move_to (lua_State *L);
|
|
|
|
static int ld_lua_cairo_line_to (lua_State *L);
|
|
|
|
static int ld_lua_cairo_stroke (lua_State *L);
|
|
|
|
static int ld_lua_cairo_stroke_preserve (lua_State *L);
|
|
|
|
static int ld_lua_cairo_fill (lua_State *L);
|
|
|
|
static int ld_lua_cairo_fill_preserve (lua_State *L);
|
2010-09-25 16:03:48 +02:00
|
|
|
|
|
|
|
static luaL_Reg ld_lua_cairo_table[] =
|
|
|
|
{
|
|
|
|
{"move_to", ld_lua_cairo_move_to},
|
|
|
|
{"line_to", ld_lua_cairo_line_to},
|
|
|
|
{"stroke", ld_lua_cairo_stroke},
|
|
|
|
{"stroke_preserve", ld_lua_cairo_stroke_preserve},
|
|
|
|
{"fill", ld_lua_cairo_fill},
|
|
|
|
{"fill_preserve", ld_lua_cairo_fill_preserve},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
|
2010-09-25 16:03:48 +02:00
|
|
|
/* ===== Generic =========================================================== */
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
static void
|
|
|
|
ld_lua_class_init (LdLuaClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class;
|
|
|
|
|
|
|
|
object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = ld_lua_finalize;
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (LdLuaPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ld_lua_init (LdLua *self)
|
2010-09-25 16:03:48 +02:00
|
|
|
{
|
|
|
|
lua_State *L;
|
2010-09-25 21:00:24 +02:00
|
|
|
LdLuaData *ud;
|
2010-09-25 16:03:48 +02:00
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE
|
|
|
|
(self, LD_TYPE_LUA, LdLuaPrivate);
|
|
|
|
|
|
|
|
L = self->priv->L = lua_newstate (ld_lua_alloc, NULL);
|
|
|
|
g_return_if_fail (L != NULL);
|
2010-09-25 16:03:48 +02:00
|
|
|
|
|
|
|
/* TODO: lua_atpanic () */
|
|
|
|
|
|
|
|
/* Load some safe libraries. */
|
|
|
|
lua_pushcfunction (L, luaopen_string);
|
|
|
|
lua_call (L, 0, 0);
|
|
|
|
|
|
|
|
lua_pushcfunction (L, luaopen_table);
|
|
|
|
lua_call (L, 0, 0);
|
|
|
|
|
|
|
|
lua_pushcfunction (L, luaopen_math);
|
|
|
|
lua_call (L, 0, 0);
|
|
|
|
|
|
|
|
/* Load the application library. */
|
2010-09-25 21:00:24 +02:00
|
|
|
luaL_register (L, LD_LUA_LIBRARY_NAME, ld_lua_logdiag_lib);
|
|
|
|
|
|
|
|
/* Store user data to the registry. */
|
|
|
|
lua_pushliteral (L, LD_LUA_DATA_INDEX);
|
|
|
|
|
|
|
|
ud = lua_newuserdata (L, sizeof (LdLuaData));
|
|
|
|
ud->self = self;
|
|
|
|
ud->category = NULL;
|
|
|
|
|
|
|
|
lua_settable (L, LUA_REGISTRYINDEX);
|
2010-09-25 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
2010-09-25 16:55:07 +02:00
|
|
|
static void
|
|
|
|
ld_lua_finalize (GObject *gobject)
|
2010-09-25 16:03:48 +02:00
|
|
|
{
|
2010-09-25 16:55:07 +02:00
|
|
|
LdLua *self;
|
|
|
|
|
|
|
|
self = LD_LUA (gobject);
|
|
|
|
lua_close (self->priv->L);
|
|
|
|
|
|
|
|
/* Chain up to the parent class. */
|
|
|
|
G_OBJECT_CLASS (ld_lua_parent_class)->finalize (gobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ld_lua_new:
|
|
|
|
*
|
2010-09-25 21:00:24 +02:00
|
|
|
* Create an instance of #LdLua.
|
2010-09-25 16:55:07 +02:00
|
|
|
*/
|
|
|
|
LdLua *
|
|
|
|
ld_lua_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (LD_TYPE_LUA, NULL);
|
2010-09-25 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
ld_lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize)
|
|
|
|
{
|
|
|
|
if (!nsize)
|
|
|
|
{
|
|
|
|
g_free (ptr);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return g_try_realloc (ptr, nsize);
|
|
|
|
}
|
|
|
|
|
2010-09-25 21:00:24 +02:00
|
|
|
/**
|
|
|
|
* ld_lua_check_file:
|
|
|
|
* @self: An #LdLua object.
|
|
|
|
* @filename: The file to be checked.
|
|
|
|
*
|
|
|
|
* Check if the given filename can be loaded by #LdLua.
|
|
|
|
*/
|
|
|
|
gboolean ld_lua_check_file (LdLua *self, const gchar *filename)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (LD_IS_LUA (self), FALSE);
|
|
|
|
return g_str_has_suffix (filename, ".lua");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ld_lua_load_file_to_category:
|
|
|
|
* @self: An #LdLua object.
|
|
|
|
* @filename: The file to be loaded.
|
|
|
|
* @category: An #LdSymbolCategory object.
|
|
|
|
*
|
|
|
|
* Loads a file and appends contained symbols into the category.
|
|
|
|
*
|
|
|
|
* Returns: TRUE if no error has occured, FALSE otherwise.
|
|
|
|
*/
|
|
|
|
gboolean ld_lua_load_file_to_category (LdLua *self, const gchar *filename,
|
|
|
|
LdSymbolCategory *category)
|
|
|
|
{
|
|
|
|
gint retval;
|
|
|
|
LdLuaData *ud;
|
|
|
|
|
|
|
|
g_return_val_if_fail (LD_IS_LUA (self), FALSE);
|
|
|
|
g_return_val_if_fail (filename != NULL, FALSE);
|
|
|
|
g_return_val_if_fail (LD_IS_SYMBOL_CATEGORY (category), FALSE);
|
|
|
|
|
|
|
|
/* TODO: Error reporting. */
|
|
|
|
|
|
|
|
ud = LD_LUA_RETRIEVE_DATA (self->priv->L);
|
|
|
|
g_return_val_if_fail (ud != NULL, FALSE);
|
|
|
|
|
|
|
|
ud->category = category;
|
|
|
|
|
|
|
|
retval = luaL_loadfile (self->priv->L, filename);
|
|
|
|
if (retval)
|
|
|
|
goto ld_lua_lftc_fail;
|
|
|
|
|
|
|
|
retval = lua_pcall (self->priv->L, 0, 0, 0);
|
|
|
|
if (retval)
|
|
|
|
goto ld_lua_lftc_fail;
|
|
|
|
|
|
|
|
ud->category = NULL;
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
ld_lua_lftc_fail:
|
|
|
|
ud->category = NULL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2010-09-25 16:03:48 +02:00
|
|
|
/* ===== Application library =============================================== */
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_logdiag_register (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
LdLuaData *ud;
|
|
|
|
LdSymbol *symbol;
|
|
|
|
|
|
|
|
ud = LD_LUA_RETRIEVE_DATA (L);
|
|
|
|
g_return_val_if_fail (ud != NULL, 0);
|
|
|
|
|
2010-09-25 16:03:48 +02:00
|
|
|
/* TODO: Create a symbol. */
|
2010-09-25 21:00:24 +02:00
|
|
|
/* XXX: Does ld_lua_symbol_new really need to be passed the category here?
|
|
|
|
* The symbol can have just a weak reference to the category.
|
2010-09-25 16:03:48 +02:00
|
|
|
*/
|
|
|
|
|
2010-09-25 21:00:24 +02:00
|
|
|
/*
|
|
|
|
symbol = ld_lua_symbol_new (ud->category, ud->self);
|
|
|
|
ld_symbol_category_insert (ud->category, symbol, -1);
|
|
|
|
g_object_unref (symbol);
|
|
|
|
*/
|
2010-09-25 16:55:07 +02:00
|
|
|
return 0;
|
2010-09-25 16:03:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ===== Cairo ============================================================= */
|
|
|
|
|
|
|
|
static void
|
|
|
|
push_cairo_object (lua_State *L, cairo_t *cr)
|
|
|
|
{
|
|
|
|
luaL_Reg *fn;
|
|
|
|
|
|
|
|
/* Create a table. */
|
|
|
|
lua_newtable (L);
|
|
|
|
|
|
|
|
/* Add methods. */
|
2010-09-25 16:55:07 +02:00
|
|
|
/* XXX: The light user data pointer gets invalid after the end of
|
|
|
|
* "render" function invocation. If the script stores the "cr" object
|
|
|
|
* in some global variable and then tries to reuse it the next time,
|
|
|
|
* the application will go SIGSEGV.
|
|
|
|
*/
|
2010-09-25 16:03:48 +02:00
|
|
|
for (fn = ld_lua_cairo_table; fn->name; fn++)
|
|
|
|
{
|
|
|
|
lua_pushlightuserdata (L, cr);
|
|
|
|
lua_pushcclosure (L, fn->func, 1);
|
|
|
|
lua_setfield (L, -2, fn->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-25 21:00:24 +02:00
|
|
|
/* TODO: More functions. Possibly put it into another file
|
|
|
|
* and generate it automatically.
|
|
|
|
*/
|
2010-09-25 16:03:48 +02:00
|
|
|
static int
|
|
|
|
ld_lua_cairo_move_to (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
lua_Number x, y;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
|
|
|
|
x = luaL_checknumber (L, 1);
|
|
|
|
y = luaL_checknumber (L, 2);
|
|
|
|
|
|
|
|
cairo_move_to (cr, x, y);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_cairo_line_to (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
lua_Number x, y;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
x = luaL_checknumber (L, 1);
|
|
|
|
y = luaL_checknumber (L, 2);
|
|
|
|
cairo_line_to (cr, x, y);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_cairo_stroke (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
cairo_stroke (cr);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_cairo_stroke_preserve (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
cairo_stroke_preserve (cr);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_cairo_fill (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
cairo_fill (cr);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
ld_lua_cairo_fill_preserve (lua_State *L)
|
|
|
|
{
|
2010-09-25 21:00:24 +02:00
|
|
|
cairo_t *cr;
|
|
|
|
|
|
|
|
cr = lua_touserdata (L, lua_upvalueindex (1));
|
|
|
|
cairo_fill_preserve (cr);
|
2010-09-25 16:03:48 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|