From 616c49a5053830a5e0a31c71fd6114926e43235f Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Mon, 10 Jan 2011 16:49:13 +0100 Subject: Make a separate library. This is required for gtkdoc-scangobj. So far it's much like it's been before, the main differences are that source files are in two directories from now on and the build process has two stages. --- src/ld-lua.c | 808 ----------------------------------------------------------- 1 file changed, 808 deletions(-) delete mode 100644 src/ld-lua.c (limited to 'src/ld-lua.c') diff --git a/src/ld-lua.c b/src/ld-lua.c deleted file mode 100644 index 47a41b5..0000000 --- a/src/ld-lua.c +++ /dev/null @@ -1,808 +0,0 @@ -/* - * ld-lua.c - * - * This file is a part of logdiag. - * Copyright Přemysl Janouch 2010 - 2011. All rights reserved. - * - * See the file LICENSE for licensing information. - * - */ - -#include -#include -#include - -#include "liblogdiag.h" -#include "config.h" - -#include "ld-lua-private.h" -#include "ld-lua-symbol-private.h" - - -/** - * SECTION:ld-lua - * @short_description: Lua symbol engine. - * @see_also: #LdLuaSymbol - * - * #LdLua is a symbol engine that uses Lua scripts to manage symbols. - */ - -/* - * LdLuaPrivate: - * @L: Lua state. - * - * The library contains the real function for rendering. - */ -struct _LdLuaPrivate -{ - lua_State *L; -}; - -/* registry.logdiag_symbols - * -> A table indexed by pointers to LdLuaSymbol objects - * registry.logdiag_symbols.object.render(cr) - * -> The rendering function - */ - -#define LD_LUA_LIBRARY_NAME "logdiag" -#define LD_LUA_DATA_INDEX LD_LUA_LIBRARY_NAME "_data" -#define LD_LUA_SYMBOLS_INDEX LD_LUA_LIBRARY_NAME "_symbols" - -/* - * LdLuaData: - * @self: A reference to self. - * @load_callback: A callback for newly registered symbols. - * @load_user_data: User data to be passed to the callback. - * - * Full user data to be stored in Lua registry. - */ -typedef struct _LdLuaData LdLuaData; - -struct _LdLuaData -{ - LdLua *self; - LdLuaLoadCallback load_callback; - gpointer load_user_data; -}; - -typedef struct _LdLuaDrawData LdLuaDrawData; - -struct _LdLuaDrawData -{ - LdLuaSymbol *symbol; - cairo_t *cr; - unsigned save_count; -}; - -static void ld_lua_finalize (GObject *gobject); - -static void *ld_lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize); - -static int ld_lua_private_draw_cb (lua_State *L); -static int ld_lua_private_unregister_cb (lua_State *L); - -static int ld_lua_logdiag_register (lua_State *L); -static int process_registration (lua_State *L); -static gchar *get_translation (lua_State *L, int index); -static gboolean read_symbol_area (lua_State *L, int index, LdRectangle *area); -static gboolean read_terminals (lua_State *L, int index, - LdPointArray **terminals); - -static void push_cairo_object (lua_State *L, LdLuaDrawData *draw_data); -static gdouble get_cairo_scale (cairo_t *cr); -static int ld_lua_cairo_save (lua_State *L); -static int ld_lua_cairo_restore (lua_State *L); -static int ld_lua_cairo_get_line_width (lua_State *L); -static int ld_lua_cairo_set_line_width (lua_State *L); -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_curve_to (lua_State *L); -static int ld_lua_cairo_arc (lua_State *L); -static int ld_lua_cairo_arc_negative (lua_State *L); -static int ld_lua_cairo_new_path (lua_State *L); -static int ld_lua_cairo_new_sub_path (lua_State *L); -static int ld_lua_cairo_close_path (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); -static int ld_lua_cairo_clip (lua_State *L); -static int ld_lua_cairo_clip_preserve (lua_State *L); - - -static luaL_Reg ld_lua_logdiag_lib[] = -{ - {"register", ld_lua_logdiag_register}, - {NULL, NULL} -}; - -static luaL_Reg ld_lua_cairo_table[] = -{ - {"save", ld_lua_cairo_save}, - {"restore", ld_lua_cairo_restore}, - {"get_line_width", ld_lua_cairo_get_line_width}, - {"set_line_width", ld_lua_cairo_set_line_width}, - {"move_to", ld_lua_cairo_move_to}, - {"line_to", ld_lua_cairo_line_to}, - {"curve_to", ld_lua_cairo_curve_to}, - {"arc", ld_lua_cairo_arc}, - {"arc_negative", ld_lua_cairo_arc_negative}, - {"new_path", ld_lua_cairo_new_path}, - {"new_sub_path", ld_lua_cairo_new_sub_path}, - {"close_path", ld_lua_cairo_close_path}, - {"stroke", ld_lua_cairo_stroke}, - {"stroke_preserve", ld_lua_cairo_stroke_preserve}, - {"fill", ld_lua_cairo_fill}, - {"fill_preserve", ld_lua_cairo_fill_preserve}, - {"clip", ld_lua_cairo_clip}, - {"clip_preserve", ld_lua_cairo_clip_preserve}, - {NULL, NULL} -}; - - -/* ===== Generic =========================================================== */ - -G_DEFINE_TYPE (LdLua, ld_lua, G_TYPE_OBJECT); - -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) -{ - lua_State *L; - LdLuaData *ud; - - 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); - - /* 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. */ - luaL_register (L, LD_LUA_LIBRARY_NAME, ld_lua_logdiag_lib); - - /* Store user data to the registry. */ - ud = lua_newuserdata (L, sizeof (LdLuaData)); - ud->self = self; - ud->load_callback = NULL; - ud->load_user_data = NULL; - - lua_setfield (L, LUA_REGISTRYINDEX, LD_LUA_DATA_INDEX); - - /* Create an empty symbol table. */ - lua_newtable (L); - lua_setfield (L, LUA_REGISTRYINDEX, LD_LUA_SYMBOLS_INDEX); -} - -static void -ld_lua_finalize (GObject *gobject) -{ - 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: - * - * Create an instance of #LdLua. - */ -LdLua * -ld_lua_new (void) -{ - return g_object_new (LD_TYPE_LUA, NULL); -} - -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); -} - -/** - * 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); - g_return_val_if_fail (filename != NULL, FALSE); - - return g_str_has_suffix (filename, ".lua") - && g_file_test (filename, G_FILE_TEST_IS_REGULAR); -} - -/** - * ld_lua_load_file: - * @self: An #LdLua object. - * @filename: The file to be loaded. - * @callback: A callback for newly registered symbols. - * The callee is responsible for referencing the symbol. - * @user_data: User data to be passed to the callback. - * - * Loads a file and creates #LdLuaSymbol objects for contained symbols. - * - * Returns: TRUE if no error has occured, FALSE otherwise. - */ -gboolean -ld_lua_load_file (LdLua *self, const gchar *filename, - LdLuaLoadCallback callback, gpointer user_data) -{ - 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 (callback != NULL, FALSE); - - /* XXX: If something from the following fails, Lua will call exit(). */ - lua_getfield (self->priv->L, LUA_REGISTRYINDEX, LD_LUA_DATA_INDEX); - ud = lua_touserdata (self->priv->L, -1); - lua_pop (self->priv->L, 1); - g_return_val_if_fail (ud != NULL, FALSE); - - ud->load_callback = callback; - ud->load_user_data = user_data; - - 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->load_callback = NULL; - ud->load_user_data = NULL; - return TRUE; - -ld_lua_lftc_fail: - g_warning ("Lua error: %s", lua_tostring (self->priv->L, -1)); - lua_remove (self->priv->L, -1); - - ud->load_callback = NULL; - ud->load_user_data = NULL; - return FALSE; -} - -/* ===== LdLuaSymbol callbacks ============================================= */ - -/** - * ld_lua_private_draw: - * @self: An #LdLua object. - * @symbol: A symbol to be drawn. - * @cr: A Cairo context to be drawn onto. - * - * Draw a symbol onto a Cairo context. - */ -void -ld_lua_private_draw (LdLua *self, LdLuaSymbol *symbol, cairo_t *cr) -{ - LdLuaDrawData data; - - g_return_if_fail (LD_IS_LUA (self)); - g_return_if_fail (LD_IS_LUA_SYMBOL (symbol)); - g_return_if_fail (cr != NULL); - - data.symbol = symbol; - data.cr = cr; - data.save_count = 0; - - if (lua_cpcall (self->priv->L, ld_lua_private_draw_cb, &data)) - { - g_warning ("Lua error: %s", lua_tostring (self->priv->L, -1)); - lua_pop (self->priv->L, 1); - } - - while (data.save_count--) - cairo_restore (cr); -} - -static int -ld_lua_private_draw_cb (lua_State *L) -{ - LdLuaDrawData *data; - - data = lua_touserdata (L, -1); - - /* Retrieve the function for rendering from the registry. */ - lua_getfield (L, LUA_REGISTRYINDEX, LD_LUA_SYMBOLS_INDEX); - lua_pushlightuserdata (L, data->symbol); - lua_gettable (L, -2); - - luaL_checktype (L, -1, LUA_TTABLE); - lua_getfield (L, -1, "render"); - luaL_checktype (L, -1, LUA_TFUNCTION); - - /* Call the function do draw the symbol. */ - push_cairo_object (L, data); - lua_pcall (L, 1, 0, 0); - return 0; -} - -/** - * ld_lua_private_unregister: - * @self: An #LdLua object. - * @symbol: A symbol to be unregistered. - * - * Unregister a symbol from the internal Lua state. - */ -void -ld_lua_private_unregister (LdLua *self, LdLuaSymbol *symbol) -{ - g_return_if_fail (LD_IS_LUA (self)); - g_return_if_fail (LD_IS_LUA_SYMBOL (symbol)); - - if (lua_cpcall (self->priv->L, ld_lua_private_unregister_cb, symbol)) - { - g_warning ("Lua error: %s", lua_tostring (self->priv->L, -1)); - lua_pop (self->priv->L, 1); - } -} - -static int -ld_lua_private_unregister_cb (lua_State *L) -{ - /* Set the entry in the symbol table to nil. */ - lua_getfield (L, LUA_REGISTRYINDEX, LD_LUA_SYMBOLS_INDEX); - lua_insert (L, -2); - lua_pushnil (L); - lua_settable (L, -3); - return 0; -} - -/* ===== Application library =============================================== */ - -static int -ld_lua_logdiag_register (lua_State *L) -{ - LdLuaData *ud; - LdLuaSymbol *symbol; - - lua_getfield (L, LUA_REGISTRYINDEX, LD_LUA_DATA_INDEX); - ud = lua_touserdata (L, -1); - lua_pop (L, 1); - g_return_val_if_fail (ud != NULL, 0); - - /* Use a protected environment, so script errors won't cause leaking - * of the symbol object. Only a failure of the last three function calls - * before lua_pcall() may cause the symbol to leak. - */ - lua_checkstack (L, 3); - symbol = g_object_new (LD_TYPE_LUA_SYMBOL, NULL); - - lua_pushlightuserdata (L, symbol); - lua_pushcclosure (L, process_registration, 1); - lua_insert (L, 1); - - /* On the stack, there are function arguments plus the function itself. */ - if (lua_pcall (L, lua_gettop (L) - 1, 0, 0)) - { - luaL_where (L, 1); - lua_insert (L, -2); - lua_concat (L, 2); - - g_warning ("Lua symbol registration failed: %s", - lua_tostring (L, -1)); - lua_pushboolean (L, FALSE); - } - else - { - /* We don't want an extra LdLua reference either. */ - symbol->priv->lua = ud->self; - g_object_ref (ud->self); - - ud->load_callback (LD_SYMBOL (symbol), ud->load_user_data); - lua_pushboolean (L, TRUE); - } - g_object_unref (symbol); - - return 1; -} - -/* - * process_registration: - * @L: A Lua state. - * - * Parse arguments, write them to a symbol object and register the object. - */ -static int -process_registration (lua_State *L) -{ - LdLuaSymbol *symbol; - gchar *human_name; - - int i, type, types[] = - {LUA_TSTRING, LUA_TTABLE, LUA_TTABLE, LUA_TTABLE, LUA_TFUNCTION}; - int n_args_needed = sizeof (types) / sizeof (int); - - if (lua_gettop (L) < n_args_needed) - return luaL_error (L, "Too few arguments."); - - for (i = 0; i < n_args_needed; i++) - if ((type = lua_type (L, i + 1)) != types[i]) - return luaL_error (L, "Bad type of argument #%d." - " Expected %s, got %s.", i + 1, - lua_typename (L, types[i]), lua_typename (L, type)); - - symbol = LD_LUA_SYMBOL (lua_touserdata (L, lua_upvalueindex (1))); - symbol->priv->name = g_strdup (lua_tostring (L, 1)); - - human_name = get_translation (L, 2); - if (!human_name) - human_name = g_strdup (symbol->priv->name); - symbol->priv->human_name = human_name; - - if (!read_symbol_area (L, 3, &symbol->priv->area)) - return luaL_error (L, "Malformed symbol area array."); - if (!read_terminals (L, 4, &symbol->priv->terminals)) - return luaL_error (L, "Malformed terminals array."); - - lua_getfield (L, LUA_REGISTRYINDEX, LD_LUA_SYMBOLS_INDEX); - lua_pushlightuserdata (L, symbol); - - lua_newtable (L); - lua_pushvalue (L, 5); - lua_setfield (L, -2, "render"); - - lua_settable (L, -3); - return 0; -} - -/* - * get_translation: - * @L: A Lua state. - * @index: Stack index of the table. - * - * Select an applicable translation from a table. - * The return value has to be freed with g_free(). - * - * Return value: The translation, if found. If none was found, returns NULL. - */ -static gchar * -get_translation (lua_State *L, int index) -{ - const gchar *const *lang; - gchar *result; - - for (lang = g_get_language_names (); *lang; lang++) - { - lua_getfield (L, 2, *lang); - if (lua_isstring (L, -1)) - { - result = g_strdup (lua_tostring (L, -1)); - lua_pop (L, 1); - return result; - } - lua_pop (L, 1); - } - return NULL; -} - -/* - * read_symbol_area: - * @L: A Lua state. - * @index: Stack index of the table. - * @area: Where the area will be returned. - * - * Read a symbol area from a Lua table. - * - * Return value: TRUE on success, FALSE on failure. - */ -static gboolean -read_symbol_area (lua_State *L, int index, LdRectangle *area) -{ - lua_Number x1, x2, y1, y2; - - if (lua_objlen (L, index) != 4) - return FALSE; - - lua_rawgeti (L, index, 1); - if (!lua_isnumber (L, -1)) - return FALSE; - x1 = lua_tonumber (L, -1); - - lua_rawgeti (L, index, 2); - if (!lua_isnumber (L, -1)) - return FALSE; - y1 = lua_tonumber (L, -1); - - lua_rawgeti (L, index, 3); - if (!lua_isnumber (L, -1)) - return FALSE; - x2 = lua_tonumber (L, -1); - - lua_rawgeti (L, index, 4); - if (!lua_isnumber (L, -1)) - return FALSE; - y2 = lua_tonumber (L, -1); - - area->x = MIN (x1, x2); - area->y = MIN (y1, y2); - area->width = ABS (x2 - x1); - area->height = ABS (y2 - y1); - - lua_pop (L, 4); - return TRUE; -} - -/* - * read_terminals: - * @L: A Lua state. - * @index: Stack index of the table. - * @area: Where the point array will be returned. - * - * Read symbol terminals from a Lua table. - * - * Return value: TRUE on success, FALSE on failure. - */ -static gboolean -read_terminals (lua_State *L, int index, LdPointArray **terminals) -{ - LdPointArray *points; - size_t num_points; - unsigned i = 0; - - num_points = lua_objlen (L, index); - points = ld_point_array_new (num_points); - - lua_pushnil (L); - while (lua_next (L, index) != 0) - { - g_assert (i < num_points); - - if (!lua_istable (L, -1) || lua_objlen (L, -1) != 2) - goto read_terminals_fail; - - lua_rawgeti (L, -1, 1); - if (!lua_isnumber (L, -1)) - goto read_terminals_fail; - points->points[i].x = lua_tonumber (L, -1); - lua_pop (L, 1); - - lua_rawgeti (L, -1, 2); - if (!lua_isnumber (L, -1)) - goto read_terminals_fail; - points->points[i].y = lua_tonumber (L, -1); - - lua_pop (L, 2); - i++; - } - *terminals = points; - return TRUE; - -read_terminals_fail: - ld_point_array_free (points); - *terminals = NULL; - return FALSE; -} - - -/* ===== Cairo ============================================================= */ - -static void -push_cairo_object (lua_State *L, LdLuaDrawData *draw_data) -{ - luaL_Reg *fn; - - /* Create a table. */ - lua_newtable (L); - - /* Add methods. */ - /* 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 may go SIGSEGV. - * - * The solution is creating a full user data instead, referencing - * the cairo object and dereferencing it upon garbage collection - * of the user data object. - */ - for (fn = ld_lua_cairo_table; fn->name; fn++) - { - lua_pushlightuserdata (L, draw_data); - lua_pushcclosure (L, fn->func, 1); - lua_setfield (L, -2, fn->name); - } -} - -static gdouble -get_cairo_scale (cairo_t *cr) -{ - double dx = 1, dy = 0; - - cairo_user_to_device_distance (cr, &dx, &dy); - return dx; -} - -#define LD_LUA_CAIRO_TRIVIAL(name) \ -static int \ -ld_lua_cairo_ ## name (lua_State *L) \ -{ \ - LdLuaDrawData *data; \ - data = lua_touserdata (L, lua_upvalueindex (1)); \ - cairo_ ## name (data->cr); \ - return 0; \ -} - -LD_LUA_CAIRO_TRIVIAL (new_path) -LD_LUA_CAIRO_TRIVIAL (new_sub_path) -LD_LUA_CAIRO_TRIVIAL (close_path) - -LD_LUA_CAIRO_TRIVIAL (stroke) -LD_LUA_CAIRO_TRIVIAL (stroke_preserve) -LD_LUA_CAIRO_TRIVIAL (fill) -LD_LUA_CAIRO_TRIVIAL (fill_preserve) -LD_LUA_CAIRO_TRIVIAL (clip) -LD_LUA_CAIRO_TRIVIAL (clip_preserve) - -static int -ld_lua_cairo_save (lua_State *L) -{ - LdLuaDrawData *data; - - data = lua_touserdata (L, lua_upvalueindex (1)); - if (data->save_count + 1) - { - data->save_count++; - cairo_save (data->cr); - } - return 0; -} - -static int -ld_lua_cairo_restore (lua_State *L) -{ - LdLuaDrawData *data; - - data = lua_touserdata (L, lua_upvalueindex (1)); - if (data->save_count) - { - data->save_count--; - cairo_restore (data->cr); - } - return 0; -} - -static int -ld_lua_cairo_get_line_width (lua_State *L) -{ - LdLuaDrawData *data; - - data = lua_touserdata (L, lua_upvalueindex (1)); - lua_pushnumber (L, cairo_get_line_width (data->cr) - * get_cairo_scale (data->cr)); - return 1; -} - -static int -ld_lua_cairo_set_line_width (lua_State *L) -{ - LdLuaDrawData *data; - - data = lua_touserdata (L, lua_upvalueindex (1)); - cairo_set_line_width (data->cr, luaL_checknumber (L, 1) - / get_cairo_scale (data->cr)); - return 0; -} - -static int -ld_lua_cairo_move_to (lua_State *L) -{ - LdLuaDrawData *data; - lua_Number x, y; - - data = lua_touserdata (L, lua_upvalueindex (1)); - - x = luaL_checknumber (L, 1); - y = luaL_checknumber (L, 2); - - cairo_move_to (data->cr, x, y); - return 0; -} - -static int -ld_lua_cairo_line_to (lua_State *L) -{ - LdLuaDrawData *data; - lua_Number x, y; - - data = lua_touserdata (L, lua_upvalueindex (1)); - - x = luaL_checknumber (L, 1); - y = luaL_checknumber (L, 2); - - cairo_line_to (data->cr, x, y); - return 0; -} - -static int -ld_lua_cairo_curve_to (lua_State *L) -{ - LdLuaDrawData *data; - lua_Number x1, y1, x2, y2, x3, y3; - - data = lua_touserdata (L, lua_upvalueindex (1)); - - x1 = luaL_checknumber (L, 1); - y1 = luaL_checknumber (L, 2); - x2 = luaL_checknumber (L, 3); - y2 = luaL_checknumber (L, 4); - x3 = luaL_checknumber (L, 5); - y3 = luaL_checknumber (L, 6); - - cairo_curve_to (data->cr, x1, y1, x2, y2, x3, y3); - return 0; -} - -static int -ld_lua_cairo_arc (lua_State *L) -{ - LdLuaDrawData *data; - lua_Number xc, yc, radius, angle1, angle2; - - data = lua_touserdata (L, lua_upvalueindex (1)); - - xc = luaL_checknumber (L, 1); - yc = luaL_checknumber (L, 2); - radius = luaL_checknumber (L, 3); - angle1 = luaL_checknumber (L, 4); - angle2 = luaL_checknumber (L, 5); - - cairo_arc (data->cr, xc, yc, radius, angle1, angle2); - return 0; -} - -static int -ld_lua_cairo_arc_negative (lua_State *L) -{ - LdLuaDrawData *data; - lua_Number xc, yc, radius, angle1, angle2; - - data = lua_touserdata (L, lua_upvalueindex (1)); - - xc = luaL_checknumber (L, 1); - yc = luaL_checknumber (L, 2); - radius = luaL_checknumber (L, 3); - angle1 = luaL_checknumber (L, 4); - angle2 = luaL_checknumber (L, 5); - - cairo_arc_negative (data->cr, xc, yc, radius, angle1, angle2); - return 0; -} - -- cgit v1.2.3-70-g09d2