682 lines
18 KiB
C
682 lines
18 KiB
C
|
/* LIBPIKA - The PIKA Library
|
||
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
||
|
*
|
||
|
* pikamodule.c
|
||
|
* (C) 1999 Austin Donnelly <austin@gimp.org>
|
||
|
*
|
||
|
* This library is free software: you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 3 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library. If not, see
|
||
|
* <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <gio/gio.h>
|
||
|
|
||
|
#include "libpikabase/pikabase.h"
|
||
|
|
||
|
#include "pikamodule.h"
|
||
|
|
||
|
#include "libpika/libpika-intl.h"
|
||
|
|
||
|
|
||
|
/**
|
||
|
* SECTION: pikamodule
|
||
|
* @title: PikaModule
|
||
|
* @short_description: A #GTypeModule subclass which implements module
|
||
|
* loading using #GModule.
|
||
|
* @see_also: #GModule, #GTypeModule
|
||
|
*
|
||
|
* #PikaModule is a generic mechanism to dynamically load modules into
|
||
|
* PIKA. It is a #GTypeModule subclass, implementing module loading
|
||
|
* using #GModule. #PikaModule does not know which functionality is
|
||
|
* implemented by the modules, it just provides a framework to get
|
||
|
* arbitrary #GType implementations loaded from disk.
|
||
|
**/
|
||
|
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
PROP_0,
|
||
|
PROP_AUTO_LOAD,
|
||
|
PROP_ON_DISK,
|
||
|
N_PROPS
|
||
|
};
|
||
|
static GParamSpec *obj_props[N_PROPS] = { NULL, };
|
||
|
|
||
|
struct _PikaModulePrivate
|
||
|
{
|
||
|
GFile *file; /* path to the module */
|
||
|
gboolean auto_load; /* auto-load the module on creation */
|
||
|
gboolean verbose; /* verbose error reporting */
|
||
|
|
||
|
PikaModuleInfo *info; /* returned values from module_query */
|
||
|
PikaModuleState state; /* what's happened to the module */
|
||
|
gchar *last_error;
|
||
|
|
||
|
gboolean on_disk; /* TRUE if file still exists */
|
||
|
|
||
|
GModule *module; /* handle on the module */
|
||
|
|
||
|
PikaModuleQueryFunc query_module;
|
||
|
PikaModuleRegisterFunc register_module;
|
||
|
};
|
||
|
|
||
|
|
||
|
static void pika_module_get_property (GObject *object,
|
||
|
guint property_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec);
|
||
|
static void pika_module_set_property (GObject *object,
|
||
|
guint property_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec);
|
||
|
static void pika_module_finalize (GObject *object);
|
||
|
|
||
|
static gboolean pika_module_load (GTypeModule *module);
|
||
|
static void pika_module_unload (GTypeModule *module);
|
||
|
|
||
|
static gboolean pika_module_open (PikaModule *module);
|
||
|
static gboolean pika_module_close (PikaModule *module);
|
||
|
static void pika_module_set_last_error (PikaModule *module,
|
||
|
const gchar *error_str);
|
||
|
|
||
|
static PikaModuleInfo * pika_module_info_new (guint32 abi_version,
|
||
|
const gchar *purpose,
|
||
|
const gchar *author,
|
||
|
const gchar *version,
|
||
|
const gchar *copyright,
|
||
|
const gchar *date);
|
||
|
static PikaModuleInfo * pika_module_info_copy (const PikaModuleInfo *info);
|
||
|
static void pika_module_info_free (PikaModuleInfo *info);
|
||
|
|
||
|
|
||
|
G_DEFINE_TYPE_WITH_PRIVATE (PikaModule, pika_module, G_TYPE_TYPE_MODULE)
|
||
|
|
||
|
#define parent_class pika_module_parent_class
|
||
|
|
||
|
|
||
|
static void
|
||
|
pika_module_class_init (PikaModuleClass *klass)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
GTypeModuleClass *module_class = G_TYPE_MODULE_CLASS (klass);
|
||
|
|
||
|
object_class->set_property = pika_module_set_property;
|
||
|
object_class->get_property = pika_module_get_property;
|
||
|
object_class->finalize = pika_module_finalize;
|
||
|
|
||
|
obj_props[PROP_AUTO_LOAD] = g_param_spec_boolean ("auto-load", "auto-load", "auto-load",
|
||
|
FALSE, PIKA_PARAM_READWRITE);
|
||
|
obj_props[PROP_ON_DISK] = g_param_spec_boolean ("on-disk", "on-disk", "on-disk",
|
||
|
FALSE, PIKA_PARAM_READABLE);
|
||
|
g_object_class_install_properties (object_class, N_PROPS, obj_props);
|
||
|
|
||
|
module_class->load = pika_module_load;
|
||
|
module_class->unload = pika_module_unload;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_init (PikaModule *module)
|
||
|
{
|
||
|
module->priv = pika_module_get_instance_private (module);
|
||
|
|
||
|
module->priv->state = PIKA_MODULE_STATE_ERROR;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_set_property (GObject *object,
|
||
|
guint property_id,
|
||
|
const GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
PikaModule *module = PIKA_MODULE (object);
|
||
|
|
||
|
switch (property_id)
|
||
|
{
|
||
|
case PROP_AUTO_LOAD:
|
||
|
pika_module_set_auto_load (module, g_value_get_boolean (value));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_get_property (GObject *object,
|
||
|
guint property_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
PikaModule *module = PIKA_MODULE (object);
|
||
|
|
||
|
switch (property_id)
|
||
|
{
|
||
|
case PROP_AUTO_LOAD:
|
||
|
g_value_set_boolean (value, pika_module_get_auto_load (module));
|
||
|
break;
|
||
|
|
||
|
case PROP_ON_DISK:
|
||
|
g_value_set_boolean (value, pika_module_is_on_disk (module));
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_finalize (GObject *object)
|
||
|
{
|
||
|
PikaModule *module = PIKA_MODULE (object);
|
||
|
|
||
|
g_clear_object (&module->priv->file);
|
||
|
g_clear_pointer (&module->priv->info, pika_module_info_free);
|
||
|
g_clear_pointer (&module->priv->last_error, g_free);
|
||
|
|
||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
pika_module_load (GTypeModule *module)
|
||
|
{
|
||
|
PikaModule *pika_module = PIKA_MODULE (module);
|
||
|
gpointer func;
|
||
|
|
||
|
g_return_val_if_fail (pika_module->priv->file != NULL, FALSE);
|
||
|
g_return_val_if_fail (pika_module->priv->module == NULL, FALSE);
|
||
|
|
||
|
if (pika_module->priv->verbose)
|
||
|
g_print ("Loading module '%s'\n",
|
||
|
pika_file_get_utf8_name (pika_module->priv->file));
|
||
|
|
||
|
if (! pika_module_open (pika_module))
|
||
|
return FALSE;
|
||
|
|
||
|
if (! pika_module_query_module (pika_module))
|
||
|
return FALSE;
|
||
|
|
||
|
/* find the pika_module_register symbol */
|
||
|
if (! g_module_symbol (pika_module->priv->module, "pika_module_register",
|
||
|
&func))
|
||
|
{
|
||
|
pika_module_set_last_error (pika_module,
|
||
|
"Missing pika_module_register() symbol");
|
||
|
|
||
|
g_message (_("Module '%s' load error: %s"),
|
||
|
pika_file_get_utf8_name (pika_module->priv->file),
|
||
|
pika_module->priv->last_error);
|
||
|
|
||
|
pika_module_close (pika_module);
|
||
|
|
||
|
pika_module->priv->state = PIKA_MODULE_STATE_ERROR;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pika_module->priv->register_module = func;
|
||
|
|
||
|
if (! pika_module->priv->register_module (module))
|
||
|
{
|
||
|
pika_module_set_last_error (pika_module,
|
||
|
"pika_module_register() returned FALSE");
|
||
|
|
||
|
g_message (_("Module '%s' load error: %s"),
|
||
|
pika_file_get_utf8_name (pika_module->priv->file),
|
||
|
pika_module->priv->last_error);
|
||
|
|
||
|
pika_module_close (pika_module);
|
||
|
|
||
|
pika_module->priv->state = PIKA_MODULE_STATE_LOAD_FAILED;
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pika_module->priv->state = PIKA_MODULE_STATE_LOADED;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_unload (GTypeModule *module)
|
||
|
{
|
||
|
PikaModule *pika_module = PIKA_MODULE (module);
|
||
|
|
||
|
g_return_if_fail (pika_module->priv->module != NULL);
|
||
|
|
||
|
if (pika_module->priv->verbose)
|
||
|
g_print ("Unloading module '%s'\n",
|
||
|
pika_file_get_utf8_name (pika_module->priv->file));
|
||
|
|
||
|
pika_module_close (pika_module);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* public functions */
|
||
|
|
||
|
/**
|
||
|
* pika_module_new:
|
||
|
* @file: A #GFile pointing to a loadable module.
|
||
|
* @auto_load: Pass %TRUE to exclude this module from auto-loading.
|
||
|
* @verbose: Pass %TRUE to enable debugging output.
|
||
|
*
|
||
|
* Creates a new #PikaModule instance.
|
||
|
*
|
||
|
* Returns: The new #PikaModule object.
|
||
|
**/
|
||
|
PikaModule *
|
||
|
pika_module_new (GFile *file,
|
||
|
gboolean auto_load,
|
||
|
gboolean verbose)
|
||
|
{
|
||
|
PikaModule *module;
|
||
|
|
||
|
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||
|
g_return_val_if_fail (g_file_is_native (file), NULL);
|
||
|
|
||
|
module = g_object_new (PIKA_TYPE_MODULE, NULL);
|
||
|
|
||
|
module->priv->file = g_object_ref (file);
|
||
|
module->priv->auto_load = auto_load ? TRUE : FALSE;
|
||
|
module->priv->verbose = verbose ? TRUE : FALSE;
|
||
|
|
||
|
if (module->priv->auto_load)
|
||
|
{
|
||
|
if (pika_module_load (G_TYPE_MODULE (module)))
|
||
|
pika_module_unload (G_TYPE_MODULE (module));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (verbose)
|
||
|
g_print ("Skipping module '%s'\n",
|
||
|
pika_file_get_utf8_name (file));
|
||
|
|
||
|
module->priv->state = PIKA_MODULE_STATE_NOT_LOADED;
|
||
|
}
|
||
|
|
||
|
return module;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_get_file:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns #GFile of the @module,
|
||
|
*
|
||
|
* Returns: (transfer none): The @module's #GFile.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
GFile *
|
||
|
pika_module_get_file (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), NULL);
|
||
|
|
||
|
return module->priv->file;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_set_auto_load:
|
||
|
* @module: A #PikaModule
|
||
|
* @auto_load: Pass %FALSE to exclude this module from auto-loading
|
||
|
*
|
||
|
* Sets the @auto_load property of the module
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
void
|
||
|
pika_module_set_auto_load (PikaModule *module,
|
||
|
gboolean auto_load)
|
||
|
{
|
||
|
g_return_if_fail (PIKA_IS_MODULE (module));
|
||
|
|
||
|
if (auto_load != module->priv->auto_load)
|
||
|
{
|
||
|
module->priv->auto_load = auto_load;
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (module), obj_props[PROP_AUTO_LOAD]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_get_auto_load:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns whether this @module in automatically loaded at startup.
|
||
|
*
|
||
|
* Returns: The @module's 'auto_load' property.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
gboolean
|
||
|
pika_module_get_auto_load (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), FALSE);
|
||
|
|
||
|
return module->priv->auto_load;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_is_on_disk:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns: Whether the @module is present on diak.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
gboolean
|
||
|
pika_module_is_on_disk (PikaModule *module)
|
||
|
{
|
||
|
gboolean old_on_disk;
|
||
|
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), FALSE);
|
||
|
|
||
|
old_on_disk = module->priv->on_disk;
|
||
|
|
||
|
module->priv->on_disk =
|
||
|
(g_file_query_file_type (module->priv->file,
|
||
|
G_FILE_QUERY_INFO_NONE, NULL) ==
|
||
|
G_FILE_TYPE_REGULAR);
|
||
|
|
||
|
if (module->priv->on_disk != old_on_disk)
|
||
|
g_object_notify_by_pspec (G_OBJECT (module), obj_props[PROP_ON_DISK]);
|
||
|
|
||
|
return module->priv->on_disk;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_is_loaded:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns: Whether the @module is currently loaded.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
gboolean
|
||
|
pika_module_is_loaded (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), FALSE);
|
||
|
|
||
|
return module->priv->module != NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_get_info:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns: (transfer none): The @module's #PikaModuleInfo as provided
|
||
|
* by the actual module, or %NULL.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
const PikaModuleInfo *
|
||
|
pika_module_get_info (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), NULL);
|
||
|
|
||
|
return module->priv->info;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_get_state:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns: The @module's state.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
PikaModuleState
|
||
|
pika_module_get_state (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), PIKA_MODULE_STATE_ERROR);
|
||
|
|
||
|
return module->priv->state;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_get_last_error:
|
||
|
* @module: A #PikaModule
|
||
|
*
|
||
|
* Returns: The @module's last error message.
|
||
|
*
|
||
|
* Since: 3.0
|
||
|
**/
|
||
|
const gchar *
|
||
|
pika_module_get_last_error (PikaModule *module)
|
||
|
{
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), NULL);
|
||
|
|
||
|
return module->priv->last_error;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_query_module:
|
||
|
* @module: A #PikaModule.
|
||
|
*
|
||
|
* Queries the module without actually registering any of the types it
|
||
|
* may implement. After successful query, pika_module_get_info() can be
|
||
|
* used to get further about the module.
|
||
|
*
|
||
|
* Returns: %TRUE on success.
|
||
|
**/
|
||
|
gboolean
|
||
|
pika_module_query_module (PikaModule *module)
|
||
|
{
|
||
|
const PikaModuleInfo *info;
|
||
|
gboolean close_module = FALSE;
|
||
|
gpointer func;
|
||
|
|
||
|
g_return_val_if_fail (PIKA_IS_MODULE (module), FALSE);
|
||
|
|
||
|
if (! module->priv->module)
|
||
|
{
|
||
|
if (! pika_module_open (module))
|
||
|
return FALSE;
|
||
|
|
||
|
close_module = TRUE;
|
||
|
}
|
||
|
|
||
|
/* find the pika_module_query symbol */
|
||
|
if (! g_module_symbol (module->priv->module, "pika_module_query", &func))
|
||
|
{
|
||
|
pika_module_set_last_error (module,
|
||
|
"Missing pika_module_query() symbol");
|
||
|
|
||
|
g_message (_("Module '%s' load error: %s"),
|
||
|
pika_file_get_utf8_name (module->priv->file),
|
||
|
module->priv->last_error);
|
||
|
|
||
|
pika_module_close (module);
|
||
|
|
||
|
module->priv->state = PIKA_MODULE_STATE_ERROR;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
module->priv->query_module = func;
|
||
|
|
||
|
g_clear_pointer (&module->priv->info, pika_module_info_free);
|
||
|
|
||
|
info = module->priv->query_module (G_TYPE_MODULE (module));
|
||
|
|
||
|
if (! info || info->abi_version != PIKA_MODULE_ABI_VERSION)
|
||
|
{
|
||
|
pika_module_set_last_error (module,
|
||
|
info ?
|
||
|
"module ABI version does not match" :
|
||
|
"pika_module_query() returned NULL");
|
||
|
|
||
|
g_message (_("Module '%s' load error: %s"),
|
||
|
pika_file_get_utf8_name (module->priv->file),
|
||
|
module->priv->last_error);
|
||
|
|
||
|
pika_module_close (module);
|
||
|
|
||
|
module->priv->state = PIKA_MODULE_STATE_ERROR;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
module->priv->info = pika_module_info_copy (info);
|
||
|
|
||
|
if (close_module)
|
||
|
return pika_module_close (module);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_error_quark:
|
||
|
*
|
||
|
* This function is never called directly. Use PIKA_MODULE_ERROR() instead.
|
||
|
*
|
||
|
* Returns: the #GQuark that defines the PIKA module error domain.
|
||
|
*
|
||
|
* Since: 2.8
|
||
|
**/
|
||
|
GQuark
|
||
|
pika_module_error_quark (void)
|
||
|
{
|
||
|
return g_quark_from_static_string ("pika-module-error-quark");
|
||
|
}
|
||
|
|
||
|
|
||
|
/* private functions */
|
||
|
|
||
|
static gboolean
|
||
|
pika_module_open (PikaModule *module)
|
||
|
{
|
||
|
gchar *path = g_file_get_path (module->priv->file);
|
||
|
|
||
|
module->priv->module = g_module_open (path, 0);
|
||
|
|
||
|
g_free (path);
|
||
|
|
||
|
if (! module->priv->module)
|
||
|
{
|
||
|
module->priv->state = PIKA_MODULE_STATE_ERROR;
|
||
|
pika_module_set_last_error (module, g_module_error ());
|
||
|
|
||
|
g_message (_("Module '%s' load error: %s"),
|
||
|
pika_file_get_utf8_name (module->priv->file),
|
||
|
module->priv->last_error);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
pika_module_close (PikaModule *module)
|
||
|
{
|
||
|
g_module_close (module->priv->module); /* FIXME: error handling */
|
||
|
module->priv->module = NULL;
|
||
|
module->priv->query_module = NULL;
|
||
|
module->priv->register_module = NULL;
|
||
|
|
||
|
module->priv->state = PIKA_MODULE_STATE_NOT_LOADED;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_module_set_last_error (PikaModule *module,
|
||
|
const gchar *error_str)
|
||
|
{
|
||
|
if (module->priv->last_error)
|
||
|
g_free (module->priv->last_error);
|
||
|
|
||
|
module->priv->last_error = g_strdup (error_str);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* PikaModuleInfo functions */
|
||
|
|
||
|
/**
|
||
|
* pika_module_info_new:
|
||
|
* @abi_version: The #PIKA_MODULE_ABI_VERSION the module was compiled against.
|
||
|
* @purpose: The module's general purpose.
|
||
|
* @author: The module's author.
|
||
|
* @version: The module's version.
|
||
|
* @copyright: The module's copyright.
|
||
|
* @date: The module's release date.
|
||
|
*
|
||
|
* Creates a newly allocated #PikaModuleInfo struct.
|
||
|
*
|
||
|
* Returns: The new #PikaModuleInfo struct.
|
||
|
**/
|
||
|
static PikaModuleInfo *
|
||
|
pika_module_info_new (guint32 abi_version,
|
||
|
const gchar *purpose,
|
||
|
const gchar *author,
|
||
|
const gchar *version,
|
||
|
const gchar *copyright,
|
||
|
const gchar *date)
|
||
|
{
|
||
|
PikaModuleInfo *info = g_slice_new0 (PikaModuleInfo);
|
||
|
|
||
|
info->abi_version = abi_version;
|
||
|
info->purpose = g_strdup (purpose);
|
||
|
info->author = g_strdup (author);
|
||
|
info->version = g_strdup (version);
|
||
|
info->copyright = g_strdup (copyright);
|
||
|
info->date = g_strdup (date);
|
||
|
|
||
|
return info;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_info_copy:
|
||
|
* @info: The #PikaModuleInfo struct to copy.
|
||
|
*
|
||
|
* Copies a #PikaModuleInfo struct.
|
||
|
*
|
||
|
* Returns: The new copy.
|
||
|
**/
|
||
|
static PikaModuleInfo *
|
||
|
pika_module_info_copy (const PikaModuleInfo *info)
|
||
|
{
|
||
|
g_return_val_if_fail (info != NULL, NULL);
|
||
|
|
||
|
return pika_module_info_new (info->abi_version,
|
||
|
info->purpose,
|
||
|
info->author,
|
||
|
info->version,
|
||
|
info->copyright,
|
||
|
info->date);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* pika_module_info_free:
|
||
|
* @info: The #PikaModuleInfo struct to free
|
||
|
*
|
||
|
* Frees the passed #PikaModuleInfo.
|
||
|
**/
|
||
|
static void
|
||
|
pika_module_info_free (PikaModuleInfo *info)
|
||
|
{
|
||
|
g_return_if_fail (info != NULL);
|
||
|
|
||
|
g_free (info->purpose);
|
||
|
g_free (info->author);
|
||
|
g_free (info->version);
|
||
|
g_free (info->copyright);
|
||
|
g_free (info->date);
|
||
|
|
||
|
g_slice_free (PikaModuleInfo, info);
|
||
|
}
|