Blame gegl/module/geglmoduledb.c

Packit Service 2781ba
/* This file is part of GEGL
Packit Service 2781ba
 *
Packit Service 2781ba
 * This library is free software; you can redistribute it and/or
Packit Service 2781ba
 * modify it under the terms of the GNU Lesser General Public
Packit Service 2781ba
 * License as published by the Free Software Foundation; either
Packit Service 2781ba
 * version 3 of the License, or (at your option) any later version.
Packit Service 2781ba
 *
Packit Service 2781ba
 * This library is distributed in the hope that it will be useful,
Packit Service 2781ba
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2781ba
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 2781ba
 * Lesser General Public License for more details.
Packit Service 2781ba
 *
Packit Service 2781ba
 * You should have received a copy of the GNU Lesser General Public
Packit Service 2781ba
 * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
Packit Service 2781ba
 */
Packit Service 2781ba
Packit Service 2781ba
#include "config.h"
Packit Service 2781ba
#include <string.h>
Packit Service 2781ba
Packit Service 2781ba
#include <glib-object.h>
Packit Service 2781ba
#include "gegl-plugin.h"
Packit Service 2781ba
#include "geglmodule.h"
Packit Service 2781ba
#include "geglmoduledb.h"
Packit Service 2781ba
#include "gegldatafiles.h"
Packit Service 2781ba
Packit Service 2781ba
enum
Packit Service 2781ba
{
Packit Service 2781ba
  ADD,
Packit Service 2781ba
  REMOVE,
Packit Service 2781ba
  MODULE_MODIFIED,
Packit Service 2781ba
  LAST_SIGNAL
Packit Service 2781ba
};
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
/*  #define DUMP_DB 1  */
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void         gegl_module_db_finalize            (GObject      *object);
Packit Service 2781ba
Packit Service 2781ba
static void         gegl_module_db_module_initialize   (const GeglDatafileData *file_data,
Packit Service 2781ba
                                                        gpointer                user_data);
Packit Service 2781ba
Packit Service 2781ba
static GeglModule * gegl_module_db_module_find_by_path (GeglModuleDB *db,
Packit Service 2781ba
                                                        const char   *fullpath);
Packit Service 2781ba
Packit Service 2781ba
#ifdef DUMP_DB
Packit Service 2781ba
static void         gegl_module_db_dump_module         (gpointer      data,
Packit Service 2781ba
                                                        gpointer      user_data);
Packit Service 2781ba
#endif
Packit Service 2781ba
Packit Service 2781ba
static void         gegl_module_db_module_on_disk_func (gpointer      data,
Packit Service 2781ba
                                                        gpointer      user_data);
Packit Service 2781ba
static void         gegl_module_db_module_remove_func  (gpointer      data,
Packit Service 2781ba
                                                        gpointer      user_data);
Packit Service 2781ba
static void         gegl_module_db_module_modified     (GeglModule   *module,
Packit Service 2781ba
                                                        GeglModuleDB *db);
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
G_DEFINE_TYPE (GeglModuleDB, gegl_module_db, G_TYPE_OBJECT)
Packit Service 2781ba
Packit Service 2781ba
#define parent_class gegl_module_db_parent_class
Packit Service 2781ba
Packit Service 2781ba
static guint db_signals[LAST_SIGNAL] = { 0 };
Packit Service 2781ba
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_class_init (GeglModuleDBClass *klass)
Packit Service 2781ba
{
Packit Service 2781ba
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service 2781ba
Packit Service 2781ba
  db_signals[ADD] =
Packit Service 2781ba
    g_signal_new ("add",
Packit Service 2781ba
                  G_TYPE_FROM_CLASS (klass),
Packit Service 2781ba
                  G_SIGNAL_RUN_FIRST,
Packit Service 2781ba
                  G_STRUCT_OFFSET (GeglModuleDBClass, add),
Packit Service 2781ba
                  NULL, NULL,
Packit Service 2781ba
                  g_cclosure_marshal_VOID__OBJECT,
Packit Service 2781ba
                  G_TYPE_NONE, 1,
Packit Service 2781ba
                  GEGL_TYPE_MODULE);
Packit Service 2781ba
Packit Service 2781ba
  db_signals[REMOVE] =
Packit Service 2781ba
    g_signal_new ("remove",
Packit Service 2781ba
                  G_TYPE_FROM_CLASS (klass),
Packit Service 2781ba
                  G_SIGNAL_RUN_FIRST,
Packit Service 2781ba
                  G_STRUCT_OFFSET (GeglModuleDBClass, remove),
Packit Service 2781ba
                  NULL, NULL,
Packit Service 2781ba
                  g_cclosure_marshal_VOID__OBJECT,
Packit Service 2781ba
                  G_TYPE_NONE, 1,
Packit Service 2781ba
                  GEGL_TYPE_MODULE);
Packit Service 2781ba
Packit Service 2781ba
  db_signals[MODULE_MODIFIED] =
Packit Service 2781ba
    g_signal_new ("module-modified",
Packit Service 2781ba
                  G_TYPE_FROM_CLASS (klass),
Packit Service 2781ba
                  G_SIGNAL_RUN_FIRST,
Packit Service 2781ba
                  G_STRUCT_OFFSET (GeglModuleDBClass, module_modified),
Packit Service 2781ba
                  NULL, NULL,
Packit Service 2781ba
                  g_cclosure_marshal_VOID__OBJECT,
Packit Service 2781ba
                  G_TYPE_NONE, 1,
Packit Service 2781ba
                  GEGL_TYPE_MODULE);
Packit Service 2781ba
Packit Service 2781ba
  object_class->finalize = gegl_module_db_finalize;
Packit Service 2781ba
Packit Service 2781ba
  klass->add             = NULL;
Packit Service 2781ba
  klass->remove          = NULL;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_init (GeglModuleDB *db)
Packit Service 2781ba
{
Packit Service 2781ba
  db->modules      = NULL;
Packit Service 2781ba
  db->load_inhibit = NULL;
Packit Service 2781ba
  db->verbose      = FALSE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_finalize (GObject *object)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModuleDB *db = GEGL_MODULE_DB (object);
Packit Service 2781ba
Packit Service 2781ba
  if (db->modules)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_list_free (db->modules);
Packit Service 2781ba
      db->modules = NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (db->load_inhibit)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_free (db->load_inhibit);
Packit Service 2781ba
      db->load_inhibit = NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  G_OBJECT_CLASS (parent_class)->finalize (object);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_module_db_new:
Packit Service 2781ba
 * @verbose: Pass %TRUE to enable debugging output.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Creates a new #GeglModuleDB instance. The @verbose parameter will be
Packit Service 2781ba
 * passed to the created #GeglModule instances using gegl_module_new().
Packit Service 2781ba
 *
Packit Service 2781ba
 * Return value: The new #GeglModuleDB instance.
Packit Service 2781ba
 **/
Packit Service 2781ba
GeglModuleDB *
Packit Service 2781ba
gegl_module_db_new (gboolean verbose)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModuleDB *db;
Packit Service 2781ba
Packit Service 2781ba
  db = g_object_new (GEGL_TYPE_MODULE_DB, NULL);
Packit Service 2781ba
Packit Service 2781ba
  db->verbose = verbose ? TRUE : FALSE;
Packit Service 2781ba
Packit Service 2781ba
  return db;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static gboolean
Packit Service 2781ba
is_in_inhibit_list (const gchar *filename,
Packit Service 2781ba
                    const gchar *inhibit_list)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar       *p;
Packit Service 2781ba
  gint         pathlen;
Packit Service 2781ba
  const gchar *start;
Packit Service 2781ba
  const gchar *end;
Packit Service 2781ba
Packit Service 2781ba
  if (! inhibit_list || ! strlen (inhibit_list))
Packit Service 2781ba
    return FALSE;
Packit Service 2781ba
Packit Service 2781ba
  p = strstr (inhibit_list, filename);
Packit Service 2781ba
  if (!p)
Packit Service 2781ba
    return FALSE;
Packit Service 2781ba
Packit Service 2781ba
  /* we have a substring, but check for colons either side */
Packit Service 2781ba
  start = p;
Packit Service 2781ba
  while (start != inhibit_list && *start != G_SEARCHPATH_SEPARATOR)
Packit Service 2781ba
    start--;
Packit Service 2781ba
Packit Service 2781ba
  if (*start == G_SEARCHPATH_SEPARATOR)
Packit Service 2781ba
    start++;
Packit Service 2781ba
Packit Service 2781ba
  end = strchr (p, G_SEARCHPATH_SEPARATOR);
Packit Service 2781ba
  if (! end)
Packit Service 2781ba
    end = inhibit_list + strlen (inhibit_list);
Packit Service 2781ba
Packit Service 2781ba
  pathlen = strlen (filename);
Packit Service 2781ba
Packit Service 2781ba
  if ((end - start) == pathlen)
Packit Service 2781ba
    return TRUE;
Packit Service 2781ba
Packit Service 2781ba
  return FALSE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_module_db_set_load_inhibit:
Packit Service 2781ba
 * @db:           A #GeglModuleDB.
Packit Service 2781ba
 * @load_inhibit: A #G_SEARCHPATH_SEPARATOR delimited list of module
Packit Service 2781ba
 *                filenames to exclude from auto-loading.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Sets the @load_inhibit flag for all #GeglModule's which are kept
Packit Service 2781ba
 * by @db (using gegl_module_set_load_inhibit()).
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_module_db_set_load_inhibit (GeglModuleDB *db,
Packit Service 2781ba
                                 const gchar  *load_inhibit)
Packit Service 2781ba
{
Packit Service 2781ba
  GList *list;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (GEGL_IS_MODULE_DB (db));
Packit Service 2781ba
Packit Service 2781ba
  if (db->load_inhibit)
Packit Service 2781ba
    g_free (db->load_inhibit);
Packit Service 2781ba
Packit Service 2781ba
  db->load_inhibit = g_strdup (load_inhibit);
Packit Service 2781ba
Packit Service 2781ba
  for (list = db->modules; list; list = g_list_next (list))
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglModule *module = list->data;
Packit Service 2781ba
Packit Service 2781ba
      gegl_module_set_load_inhibit (module,
Packit Service 2781ba
                                    is_in_inhibit_list (module->filename,
Packit Service 2781ba
                                                        load_inhibit));
Packit Service 2781ba
    }
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_module_db_get_load_inhibit:
Packit Service 2781ba
 * @db: A #GeglModuleDB.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Return the #G_SEARCHPATH_SEPARATOR selimited list of module filenames
Packit Service 2781ba
 * which are excluded from auto-loading.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Return value: the @db's @load_inhibit string.
Packit Service 2781ba
 **/
Packit Service 2781ba
const gchar *
Packit Service 2781ba
gegl_module_db_get_load_inhibit (GeglModuleDB *db)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_val_if_fail (GEGL_IS_MODULE_DB (db), NULL);
Packit Service 2781ba
Packit Service 2781ba
  return db->load_inhibit;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_module_db_load:
Packit Service 2781ba
 * @db:          A #GeglModuleDB.
Packit Service 2781ba
 * @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
Packit Service 2781ba
 *               to load modules from.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Scans the directories contained in @module_path using
Packit Service 2781ba
 * gegl_datafiles_read_directories() and creates a #GeglModule
Packit Service 2781ba
 * instance for every loadable module contained in the directories.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_module_db_load (GeglModuleDB *db,
Packit Service 2781ba
                     const gchar  *module_path)
Packit Service 2781ba
{
Packit Service 2781ba
  g_return_if_fail (GEGL_IS_MODULE_DB (db));
Packit Service 2781ba
  g_return_if_fail (module_path != NULL);
Packit Service 2781ba
Packit Service 2781ba
  if (g_module_supported ())
Packit Service 2781ba
    gegl_datafiles_read_directories (module_path,
Packit Service 2781ba
                                     G_FILE_TEST_EXISTS,
Packit Service 2781ba
                                     gegl_module_db_module_initialize,
Packit Service 2781ba
                                     db);
Packit Service 2781ba
Packit Service 2781ba
#ifdef DUMP_DB
Packit Service 2781ba
  g_list_foreach (db->modules, gegl_module_db_dump_module, NULL);
Packit Service 2781ba
#endif
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/**
Packit Service 2781ba
 * gegl_module_db_refresh:
Packit Service 2781ba
 * @db:          A #GeglModuleDB.
Packit Service 2781ba
 * @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
Packit Service 2781ba
 *               to load modules from.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Does the same as gegl_module_db_load(), plus removes all #GeglModule
Packit Service 2781ba
 * instances whose modules have been deleted from disk.
Packit Service 2781ba
 *
Packit Service 2781ba
 * Note that the #GeglModule's will just be removed from the internal
Packit Service 2781ba
 * list and not freed as this is not possible with #GTypeModule
Packit Service 2781ba
 * instances which actually implement types.
Packit Service 2781ba
 **/
Packit Service 2781ba
void
Packit Service 2781ba
gegl_module_db_refresh (GeglModuleDB *db,
Packit Service 2781ba
                        const gchar  *module_path)
Packit Service 2781ba
{
Packit Service 2781ba
  GList *kill_list = NULL;
Packit Service 2781ba
Packit Service 2781ba
  g_return_if_fail (GEGL_IS_MODULE_DB (db));
Packit Service 2781ba
  g_return_if_fail (module_path != NULL);
Packit Service 2781ba
Packit Service 2781ba
  /* remove modules we don't have on disk anymore */
Packit Service 2781ba
  g_list_foreach (db->modules,
Packit Service 2781ba
                  gegl_module_db_module_on_disk_func,
Packit Service 2781ba
                  &kill_list);
Packit Service 2781ba
  g_list_foreach (kill_list,
Packit Service 2781ba
                  gegl_module_db_module_remove_func,
Packit Service 2781ba
                  db);
Packit Service 2781ba
  g_list_free (kill_list);
Packit Service 2781ba
Packit Service 2781ba
  /* walk filesystem and add new things we find */
Packit Service 2781ba
  gegl_datafiles_read_directories (module_path,
Packit Service 2781ba
                                   G_FILE_TEST_EXISTS,
Packit Service 2781ba
                                   gegl_module_db_module_initialize,
Packit Service 2781ba
                                   db);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
/* name must be of the form lib*.so (Unix) or *.dll (Win32) */
Packit Service 2781ba
static gboolean
Packit Service 2781ba
valid_module_name (const gchar *filename)
Packit Service 2781ba
{
Packit Service 2781ba
  gchar *basename = g_path_get_basename (filename);
Packit Service 2781ba
Packit Service 2781ba
  if (! gegl_datafiles_check_extension (basename, "." G_MODULE_SUFFIX))
Packit Service 2781ba
    {
Packit Service 2781ba
      g_free (basename);
Packit Service 2781ba
Packit Service 2781ba
      return FALSE;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  g_free (basename);
Packit Service 2781ba
Packit Service 2781ba
  return TRUE;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_module_initialize (const GeglDatafileData *file_data,
Packit Service 2781ba
                                  gpointer                user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModuleDB *db = GEGL_MODULE_DB (user_data);
Packit Service 2781ba
  GeglModule   *module;
Packit Service 2781ba
  gboolean      load_inhibit;
Packit Service 2781ba
Packit Service 2781ba
  if (! valid_module_name (file_data->filename))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  /* don't load if we already know about it */
Packit Service 2781ba
  if (gegl_module_db_module_find_by_path (db, file_data->filename))
Packit Service 2781ba
    return;
Packit Service 2781ba
Packit Service 2781ba
  load_inhibit = is_in_inhibit_list (file_data->filename,
Packit Service 2781ba
                                     db->load_inhibit);
Packit Service 2781ba
Packit Service 2781ba
  module = gegl_module_new (file_data->filename,
Packit Service 2781ba
                            load_inhibit,
Packit Service 2781ba
                            db->verbose);
Packit Service 2781ba
Packit Service 2781ba
  g_signal_connect (module, "modified",
Packit Service 2781ba
                    G_CALLBACK (gegl_module_db_module_modified),
Packit Service 2781ba
                    db);
Packit Service 2781ba
Packit Service 2781ba
  db->modules = g_list_append (db->modules, module);
Packit Service 2781ba
  g_signal_emit (db, db_signals[ADD], 0, module);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static GeglModule *
Packit Service 2781ba
gegl_module_db_module_find_by_path (GeglModuleDB *db,
Packit Service 2781ba
                                    const char   *fullpath)
Packit Service 2781ba
{
Packit Service 2781ba
  GList *list;
Packit Service 2781ba
Packit Service 2781ba
  for (list = db->modules; list; list = g_list_next (list))
Packit Service 2781ba
    {
Packit Service 2781ba
      GeglModule *module = list->data;
Packit Service 2781ba
Packit Service 2781ba
      if (! strcmp (module->filename, fullpath))
Packit Service 2781ba
        return module;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  return NULL;
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
#ifdef DUMP_DB
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_dump_module (gpointer data,
Packit Service 2781ba
                            gpointer user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModule *module = data;
Packit Service 2781ba
Packit Service 2781ba
  g_print ("\n%s: %s\n",
Packit Service 2781ba
           module->filename,
Packit Service 2781ba
           gegl_module_state_name (module->state));
Packit Service 2781ba
Packit Service 2781ba
  g_print ("  module: %p  lasterr: %s  query: %p register: %p\n",
Packit Service 2781ba
           module->module,
Packit Service 2781ba
           module->last_module_error ? module->last_module_error : "NONE",
Packit Service 2781ba
           module->query_module,
Packit Service 2781ba
           module->register_module);
Packit Service 2781ba
}
Packit Service 2781ba
#endif
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_module_on_disk_func (gpointer data,
Packit Service 2781ba
                                    gpointer user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModule  *module    = data;
Packit Service 2781ba
  GList      **kill_list = user_data;
Packit Service 2781ba
  gboolean     old_on_disk;
Packit Service 2781ba
Packit Service 2781ba
  old_on_disk = module->on_disk;
Packit Service 2781ba
Packit Service 2781ba
  module->on_disk = g_file_test (module->filename, G_FILE_TEST_IS_REGULAR);
Packit Service 2781ba
Packit Service 2781ba
  /* if it's not on the disk, and it isn't in memory, mark it to be
Packit Service 2781ba
   * removed later.
Packit Service 2781ba
   */
Packit Service 2781ba
  if (! module->on_disk && ! module->module)
Packit Service 2781ba
    {
Packit Service 2781ba
      *kill_list = g_list_append (*kill_list, module);
Packit Service 2781ba
      module = NULL;
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  if (module && module->on_disk != old_on_disk)
Packit Service 2781ba
    gegl_module_modified (module);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_module_remove_func (gpointer data,
Packit Service 2781ba
                                   gpointer user_data)
Packit Service 2781ba
{
Packit Service 2781ba
  GeglModule   *module = data;
Packit Service 2781ba
  GeglModuleDB *db     = user_data;
Packit Service 2781ba
Packit Service 2781ba
  g_signal_handlers_disconnect_by_func (module,
Packit Service 2781ba
                                        gegl_module_db_module_modified,
Packit Service 2781ba
                                        db);
Packit Service 2781ba
Packit Service 2781ba
  db->modules = g_list_remove (db->modules, module);
Packit Service 2781ba
Packit Service 2781ba
  g_signal_emit (db, db_signals[REMOVE], 0, module);
Packit Service 2781ba
}
Packit Service 2781ba
Packit Service 2781ba
static void
Packit Service 2781ba
gegl_module_db_module_modified (GeglModule   *module,
Packit Service 2781ba
                                GeglModuleDB *db)
Packit Service 2781ba
{
Packit Service 2781ba
  g_signal_emit (db, db_signals[MODULE_MODIFIED], 0, module);
Packit Service 2781ba
}