logdiag/src/ld-library.c

448 lines
9.9 KiB
C
Raw Normal View History

2010-09-13 19:24:53 +02:00
/*
2010-09-25 16:14:09 +02:00
* ld-library.c
2010-09-13 19:24:53 +02:00
*
* This file is a part of logdiag.
* Copyright Přemysl Janouch 2010. All rights reserved.
*
* See the file LICENSE for licensing information.
*
*/
2010-12-05 15:21:00 +01:00
#include <string.h>
2010-09-13 19:24:53 +02:00
#include <gtk/gtk.h>
#include "config.h"
#include "ld-symbol.h"
#include "ld-symbol-category.h"
#include "ld-library.h"
2010-09-25 16:55:07 +02:00
#include "ld-lua.h"
2010-09-13 19:24:53 +02:00
/**
2010-09-25 16:14:09 +02:00
* SECTION:ld-library
2010-09-13 19:24:53 +02:00
* @short_description: A symbol library.
* @see_also: #LdSymbol, #LdSymbolCategory
2010-09-13 19:24:53 +02:00
*
2010-09-25 16:14:09 +02:00
* #LdLibrary is used for loading symbols from their files.
2010-09-13 19:24:53 +02:00
*/
/*
2010-09-25 16:14:09 +02:00
* LdLibraryPrivate:
* @lua: State of the scripting language.
* @children: Child objects of the library.
2010-09-13 19:24:53 +02:00
*/
2010-09-25 16:14:09 +02:00
struct _LdLibraryPrivate
2010-09-13 19:24:53 +02:00
{
2010-09-25 16:55:07 +02:00
LdLua *lua;
GSList *children;
2010-09-13 19:24:53 +02:00
};
2010-09-25 16:14:09 +02:00
G_DEFINE_TYPE (LdLibrary, ld_library, G_TYPE_OBJECT);
2010-09-13 19:24:53 +02:00
static void
2010-09-25 16:14:09 +02:00
ld_library_finalize (GObject *gobject);
2010-09-13 19:24:53 +02:00
static LdSymbolCategory *load_category
(LdLibrary *self, const char *path, const char *name);
static gboolean foreach_dir (const gchar *path,
gboolean (*callback) (const gchar *, const gchar *, gpointer),
gpointer userdata, GError **error);
static gboolean load_category_cb (const gchar *base,
const gchar *filename, gpointer userdata);
static void load_category_symbol_cb (LdSymbol *symbol, gpointer user_data);
static gboolean ld_library_load_cb
(const gchar *base, const gchar *filename, gpointer userdata);
2010-09-13 19:24:53 +02:00
static void
2010-09-25 16:14:09 +02:00
ld_library_class_init (LdLibraryClass *klass)
2010-09-13 19:24:53 +02:00
{
GObjectClass *object_class;
object_class = G_OBJECT_CLASS (klass);
2010-09-25 16:14:09 +02:00
object_class->finalize = ld_library_finalize;
2010-09-13 19:24:53 +02:00
/**
2010-09-25 16:14:09 +02:00
* LdLibrary::changed:
2010-09-13 19:24:53 +02:00
* @library: The library object.
*
* Contents of the library have changed.
*/
klass->changed_signal = g_signal_new
2010-12-05 15:21:00 +01:00
("changed", G_TYPE_FROM_CLASS (klass),
2010-09-13 19:24:53 +02:00
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
2010-09-25 16:14:09 +02:00
g_type_class_add_private (klass, sizeof (LdLibraryPrivate));
2010-09-13 19:24:53 +02:00
}
static void
2010-09-25 16:14:09 +02:00
ld_library_init (LdLibrary *self)
2010-09-13 19:24:53 +02:00
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE
2010-09-25 16:14:09 +02:00
(self, LD_TYPE_LIBRARY, LdLibraryPrivate);
2010-09-13 19:24:53 +02:00
2010-09-25 16:55:07 +02:00
self->priv->lua = ld_lua_new ();
self->priv->children = NULL;
2010-09-13 19:24:53 +02:00
}
static void
2010-09-25 16:14:09 +02:00
ld_library_finalize (GObject *gobject)
2010-09-13 19:24:53 +02:00
{
2010-09-25 16:14:09 +02:00
LdLibrary *self;
2010-09-13 19:24:53 +02:00
2010-09-25 16:14:09 +02:00
self = LD_LIBRARY (gobject);
2010-09-13 19:24:53 +02:00
2010-09-25 16:55:07 +02:00
g_object_unref (self->priv->lua);
g_slist_foreach (self->priv->children, (GFunc) g_object_unref, NULL);
g_slist_free (self->priv->children);
2010-09-13 19:24:53 +02:00
/* Chain up to the parent class. */
2010-09-25 16:14:09 +02:00
G_OBJECT_CLASS (ld_library_parent_class)->finalize (gobject);
2010-09-13 19:24:53 +02:00
}
/**
2010-09-25 16:14:09 +02:00
* ld_library_new:
2010-09-13 19:24:53 +02:00
*
* Create an instance.
*/
2010-09-25 16:14:09 +02:00
LdLibrary *
ld_library_new (void)
2010-09-13 19:24:53 +02:00
{
2010-09-25 16:14:09 +02:00
return g_object_new (LD_TYPE_LIBRARY, NULL);
2010-09-13 19:24:53 +02:00
}
/*
* foreach_dir:
*
* Call a user-defined function for each file within a directory.
*/
static gboolean
foreach_dir (const gchar *path,
gboolean (*callback) (const gchar *, const gchar *, gpointer),
gpointer userdata, GError **error)
{
GDir *dir;
const gchar *item;
/* FIXME: We don't set an error. */
g_return_val_if_fail (path != NULL, FALSE);
g_return_val_if_fail (callback != NULL, FALSE);
dir = g_dir_open (path, 0, error);
if (!dir)
return FALSE;
while ((item = g_dir_read_name (dir)))
{
gchar *filename;
filename = g_build_filename (path, item, NULL);
if (!callback (item, filename, userdata))
break;
g_free (filename);
}
g_dir_close (dir);
return TRUE;
}
/*
* LoadCategoryData:
*
* Data shared between load_category() and load_category_cb().
*/
typedef struct
{
LdLibrary *self;
LdSymbolCategory *cat;
}
LoadCategoryData;
2010-09-13 19:24:53 +02:00
/*
* load_category:
* @self: A symbol library object.
* @path: The path to the category.
* @name: The default name of the category.
*
* Loads a category into the library.
*/
static LdSymbolCategory *
2010-09-25 16:14:09 +02:00
load_category (LdLibrary *self, const char *path, const char *name)
2010-09-13 19:24:53 +02:00
{
LdSymbolCategory *cat;
2010-09-13 19:24:53 +02:00
gchar *icon_file;
LoadCategoryData data;
2010-09-13 19:24:53 +02:00
2010-09-25 16:14:09 +02:00
g_return_val_if_fail (LD_IS_LIBRARY (self), NULL);
2010-09-13 19:24:53 +02:00
g_return_val_if_fail (path != NULL, NULL);
g_return_val_if_fail (name != NULL, NULL);
if (!g_file_test (path, G_FILE_TEST_IS_DIR))
goto load_category_fail_1;
2010-09-13 19:24:53 +02:00
icon_file = g_build_filename (path, "icon.svg", NULL);
if (!g_file_test (icon_file, G_FILE_TEST_IS_REGULAR))
{
g_warning ("The category in %s has no icon.", path);
goto load_category_fail_2;
2010-09-13 19:24:53 +02:00
}
/* TODO: Search for category.json and read the category name from it. */
cat = ld_symbol_category_new (name);
ld_symbol_category_set_image_path (cat, icon_file);
data.self = self;
data.cat = cat;
foreach_dir (path, load_category_cb, &data, NULL);
g_free (icon_file);
2010-09-13 19:24:53 +02:00
return cat;
load_category_fail_2:
g_free (icon_file);
load_category_fail_1:
return NULL;
2010-09-13 19:24:53 +02:00
}
/*
* load_category_cb:
*
* Load script files from a directory into a symbol category.
*/
static gboolean
load_category_cb (const gchar *base, const gchar *filename, gpointer userdata)
{
LoadCategoryData *data;
g_return_val_if_fail (base != NULL, FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (userdata != NULL, FALSE);
data = (LoadCategoryData *) userdata;
if (ld_lua_check_file (data->self->priv->lua, filename))
ld_lua_load_file (data->self->priv->lua, filename,
load_category_symbol_cb, data->cat);
return TRUE;
}
/*
* load_category_symbol_cb:
*
* Insert newly registered symbols into the category.
*/
static void
load_category_symbol_cb (LdSymbol *symbol, gpointer user_data)
{
/* TODO: Don't just add blindly, also check for name collisions. */
ld_symbol_category_insert_child
(LD_SYMBOL_CATEGORY (user_data), G_OBJECT (symbol), -1);
}
/*
* LibraryLoadData:
*
* Data shared between ld_library_load() and ld_library_load_cb().
*/
typedef struct
{
LdLibrary *self;
gboolean changed;
}
LibraryLoadData;
2010-09-13 19:24:53 +02:00
/**
2010-09-25 16:14:09 +02:00
* ld_library_load:
2010-09-13 19:24:53 +02:00
* @self: A symbol library object.
* @directory: A directory to be loaded.
*
* Load the contents of a directory into the library.
*/
gboolean
2010-09-25 16:14:09 +02:00
ld_library_load (LdLibrary *self, const char *path)
2010-09-13 19:24:53 +02:00
{
LibraryLoadData data;
2010-09-13 19:24:53 +02:00
2010-09-25 16:14:09 +02:00
g_return_val_if_fail (LD_IS_LIBRARY (self), FALSE);
2010-09-13 19:24:53 +02:00
g_return_val_if_fail (path != NULL, FALSE);
data.self = self;
data.changed = FALSE;
foreach_dir (path, ld_library_load_cb, &data, NULL);
2010-09-13 19:24:53 +02:00
if (data.changed)
g_signal_emit (self, LD_LIBRARY_GET_CLASS (self)->changed_signal, 0);
2010-09-13 19:24:53 +02:00
return TRUE;
}
/*
* ld_library_load_cb:
*
* A callback that's called for each file in the root directory.
*/
static gboolean
ld_library_load_cb (const gchar *base, const gchar *filename, gpointer userdata)
{
LdSymbolCategory *cat;
gchar *categ_path;
LibraryLoadData *data;
g_return_val_if_fail (base != NULL, FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
g_return_val_if_fail (userdata != NULL, FALSE);
data = (LibraryLoadData *) userdata;
cat = load_category (data->self, filename, base);
if (cat)
ld_library_insert_child (data->self, G_OBJECT (cat), -1);
data->changed = TRUE;
2010-09-13 19:24:53 +02:00
return TRUE;
}
/**
* ld_library_find_symbol:
* @self: A symbol library object.
* @identifier: An identifier of the symbol to be searched for.
*
* Search for a symbol in the library.
*
* Return value: A symbol object if found, NULL otherwise.
*/
/* XXX: With this level of indentation, this function is really ugly. */
LdSymbol *
ld_library_find_symbol (LdLibrary *self, const gchar *identifier)
{
gchar **id_el_start, **id_el;
const GSList *list, *list_el;
g_return_val_if_fail (LD_IS_LIBRARY (self), NULL);
g_return_val_if_fail (identifier != NULL, NULL);
id_el_start = g_strsplit (identifier, LD_LIBRARY_IDENTIFIER_SEPARATOR, 0);
if (!id_el_start)
return NULL;
list = ld_library_get_children (self);
for (id_el = id_el_start; id_el[0]; id_el++)
{
LdSymbolCategory *cat;
LdSymbol *symbol;
gboolean found = FALSE;
for (list_el = list; list_el; list_el = g_slist_next (list_el))
{
/* If the current identifier element is a category (not last)
* and this list element is a category.
*/
if (id_el[1] && LD_IS_SYMBOL_CATEGORY (list_el->data))
{
cat = LD_SYMBOL_CATEGORY (list_el->data);
if (strcmp (id_el[0], ld_symbol_category_get_name (cat)))
continue;
list = ld_symbol_category_get_children (cat);
found = TRUE;
break;
}
/* If the current identifier element is a symbol (last)
* and this list element is a symbol.
*/
else if (!id_el[1] && LD_IS_SYMBOL (list_el->data))
{
symbol = LD_SYMBOL (list_el->data);
if (strcmp (id_el[0], ld_symbol_get_name (symbol)))
continue;
g_strfreev (id_el_start);
return symbol;
}
}
if (!found)
break;
}
g_strfreev (id_el_start);
return NULL;
}
2010-09-13 19:24:53 +02:00
/**
2010-09-25 16:14:09 +02:00
* ld_library_clear:
* @self: A symbol library object.
2010-09-13 19:24:53 +02:00
*
* Clears all the contents.
*/
void
2010-09-25 16:14:09 +02:00
ld_library_clear (LdLibrary *self)
2010-09-13 19:24:53 +02:00
{
2010-09-25 16:14:09 +02:00
g_return_if_fail (LD_IS_LIBRARY (self));
2010-09-13 19:24:53 +02:00
g_slist_foreach (self->priv->children, (GFunc) g_object_unref, NULL);
g_slist_free (self->priv->children);
self->priv->children = NULL;
g_signal_emit (self,
2010-09-25 16:14:09 +02:00
LD_LIBRARY_GET_CLASS (self)->changed_signal, 0);
2010-09-13 19:24:53 +02:00
}
/**
* ld_library_insert_child:
* @self: An #LdLibrary object.
* @child: The child to be inserted.
* @pos: The position at which the child will be inserted.
* Negative values will append to the end of list.
*
* Insert a child into the library.
*/
void
ld_library_insert_child (LdLibrary *self, GObject *child, gint pos)
{
g_return_if_fail (LD_IS_LIBRARY (self));
g_return_if_fail (G_IS_OBJECT (child));
g_object_ref (child);
self->priv->children = g_slist_insert (self->priv->children, child, pos);
}
/**
* ld_library_remove_child:
* @self: An #LdLibrary object.
* @child: The child to be removed.
*
* Removes a child from the library.
*/
void
ld_library_remove_child (LdLibrary *self, GObject *child)
{
g_return_if_fail (LD_IS_LIBRARY (self));
g_return_if_fail (G_IS_OBJECT (child));
2010-12-05 15:21:00 +01:00
if (g_slist_find (self->priv->children, child))
{
g_object_unref (child);
self->priv->children = g_slist_remove (self->priv->children, child);
}
}
/**
* ld_library_get_children:
* @self: An #LdLibrary object.
*
* Return value: The internal list of children. Do not modify.
*/
const GSList *
ld_library_get_children (LdLibrary *self)
{
g_return_val_if_fail (LD_IS_LIBRARY (self), NULL);
return self->priv->children;
}