Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

11
libpikamodule/Makefile.gi Normal file
View File

@ -0,0 +1,11 @@
# Introspectable sources for libpikamodule
libpikamodule_introspectable_headers = \
../libpikamodule/pikamoduletypes.h \
../libpikamodule/pikamodule.h \
../libpikamodule/pikamoduledb.h
libpikamodule_introspectable = \
../libpikamodule/pikamodule.c \
../libpikamodule/pikamoduledb.c \
$(libpikamodule_introspectable_headers)

37
libpikamodule/meson.build Normal file
View File

@ -0,0 +1,37 @@
libpikamodule_sources = files(
'pikamodule.c',
'pikamoduledb.c',
)
libpikamodule_headers = files(
'pikamodule.h',
'pikamoduledb.h',
'pikamoduletypes.h',
)
libpikamodule_introspectable = [
libpikamodule_sources,
libpikamodule_headers,
]
libpikamodule = library('pikamodule-' + pika_api_version,
libpikamodule_sources,
include_directories: rootInclude,
dependencies: [
gio, glib, gmodule,
],
c_args: [ '-DG_LOG_DOMAIN="LibPikaModule"', '-DPIKA_MODULE_COMPILATION', ],
link_with: [
libpikabase,
libpikaconfig,
],
vs_module_defs: 'pikamodule.def',
install: true,
version: so_version,
)
install_headers(
libpikamodule_headers,
subdir: pika_api_name / 'libpikamodule',
)

681
libpikamodule/pikamodule.c Normal file
View File

@ -0,0 +1,681 @@
/* 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);
}

View File

@ -0,0 +1,21 @@
EXPORTS
pika_module_db_get_load_inhibit
pika_module_db_get_type
pika_module_db_get_verbose
pika_module_db_load
pika_module_db_new
pika_module_db_refresh
pika_module_db_set_load_inhibit
pika_module_db_set_verbose
pika_module_error_quark
pika_module_get_auto_load
pika_module_get_file
pika_module_get_info
pika_module_get_last_error
pika_module_get_state
pika_module_get_type
pika_module_is_loaded
pika_module_is_on_disk
pika_module_new
pika_module_query_module
pika_module_set_auto_load

214
libpikamodule/pikamodule.h Normal file
View File

@ -0,0 +1,214 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikamodule.h
* (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/>.
*/
#ifndef __PIKA_MODULE_H__
#define __PIKA_MODULE_H__
#include <gio/gio.h>
#include <gmodule.h>
#define __PIKA_MODULE_H_INSIDE__
#include <libpikamodule/pikamoduletypes.h>
#include <libpikamodule/pikamoduledb.h>
#undef __PIKA_MODULE_H_INSIDE__
G_BEGIN_DECLS
/**
* PIKA_MODULE_ABI_VERSION:
*
* The version of the module system's ABI. Modules put this value into
* #PikaModuleInfo's @abi_version field so the code loading the modules
* can check if it was compiled against the same module ABI the modules
* are compiled against.
*
* PIKA_MODULE_ABI_VERSION is incremented each time one of the
* following changes:
*
* - the libpikamodule implementation (if the change affects modules).
*
* - one of the classes implemented by modules (currently #PikaColorDisplay,
* #PikaColorSelector and #PikaController).
**/
#define PIKA_MODULE_ABI_VERSION 0x0005
/**
* PikaModuleState:
* @PIKA_MODULE_STATE_ERROR: Missing pika_module_register() function
* or other error.
* @PIKA_MODULE_STATE_LOADED: An instance of a type implemented by
* this module is allocated.
* @PIKA_MODULE_STATE_LOAD_FAILED: pika_module_register() returned %FALSE.
* @PIKA_MODULE_STATE_NOT_LOADED: There are no instances allocated of
* types implemented by this module.
*
* The possible states a #PikaModule can be in.
**/
typedef enum
{
PIKA_MODULE_STATE_ERROR,
PIKA_MODULE_STATE_LOADED,
PIKA_MODULE_STATE_LOAD_FAILED,
PIKA_MODULE_STATE_NOT_LOADED
} PikaModuleState;
#define PIKA_MODULE_ERROR (pika_module_error_quark ())
GQuark pika_module_error_quark (void) G_GNUC_CONST;
/**
* PikaModuleError:
* @PIKA_MODULE_FAILED: Generic error condition
*
* Types of errors returned by modules
**/
typedef enum
{
PIKA_MODULE_FAILED
} PikaModuleError;
/**
* PikaModuleInfo:
* @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.
*
* This structure contains information about a loadable module.
**/
struct _PikaModuleInfo
{
guint32 abi_version;
gchar *purpose;
gchar *author;
gchar *version;
gchar *copyright;
gchar *date;
};
/**
* PikaModuleQueryFunc:
* @module: The module responsible for this loadable module.
*
* The signature of the query function a loadable PIKA module must
* implement. In the module, the function must be called [func@Module.query].
*
* [class@Module] will copy the returned [struct@ModuleInfo], so the
* module doesn't need to keep these values around (however in most
* cases the module will just return a pointer to a constant
* structure).
*
* Returns: The info struct describing the module.
**/
typedef const PikaModuleInfo * (* PikaModuleQueryFunc) (GTypeModule *module);
/**
* PikaModuleRegisterFunc:
* @module: The module responsible for this loadable module.
*
* The signature of the register function a loadable PIKA module must
* implement. In the module, the function must be called
* [func@Module.register].
*
* When this function is called, the module should register all the types
* it implements with the passed @module.
*
* Returns: Whether the registration was succesfull
**/
typedef gboolean (* PikaModuleRegisterFunc) (GTypeModule *module);
/* PikaModules have to implement these */
G_MODULE_EXPORT const PikaModuleInfo * pika_module_query (GTypeModule *module);
G_MODULE_EXPORT gboolean pika_module_register (GTypeModule *module);
#define PIKA_TYPE_MODULE (pika_module_get_type ())
#define PIKA_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_MODULE, PikaModule))
#define PIKA_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_MODULE, PikaModuleClass))
#define PIKA_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_MODULE))
#define PIKA_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_MODULE))
#define PIKA_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_MODULE, PikaModuleClass))
typedef struct _PikaModulePrivate PikaModulePrivate;
typedef struct _PikaModuleClass PikaModuleClass;
struct _PikaModule
{
GTypeModule parent_instance;
PikaModulePrivate *priv;
};
struct _PikaModuleClass
{
GTypeModuleClass parent_class;
void (* modified) (PikaModule *module);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_module_get_type (void) G_GNUC_CONST;
PikaModule * pika_module_new (GFile *file,
gboolean auto_load,
gboolean verbose);
GFile * pika_module_get_file (PikaModule *module);
void pika_module_set_auto_load (PikaModule *module,
gboolean auto_load);
gboolean pika_module_get_auto_load (PikaModule *module);
gboolean pika_module_is_on_disk (PikaModule *module);
gboolean pika_module_is_loaded (PikaModule *module);
const PikaModuleInfo * pika_module_get_info (PikaModule *module);
PikaModuleState pika_module_get_state (PikaModule *module);
const gchar * pika_module_get_last_error (PikaModule *module);
gboolean pika_module_query_module (PikaModule *module);
G_END_DECLS
#endif /* __PIKA_MODULE_H__ */

View File

@ -0,0 +1,484 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* 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 "libpikaconfig/pikaconfig.h"
#include "pikamoduletypes.h"
#include "pikamodule.h"
#include "pikamoduledb.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikamoduledb
* @title: PikaModuleDB
* @short_description: Keeps a list of #PikaModule's found in a given
* searchpath.
*
* Keeps a list of #PikaModule's found in a given searchpath.
**/
struct _PikaModuleDB
{
GObject parent_instance;
GPtrArray *modules;
gchar *load_inhibit;
gboolean verbose;
};
static void pika_module_db_finalize (GObject *object);
static void pika_module_db_load_directory (PikaModuleDB *db,
GFile *directory);
static void pika_module_db_load_module (PikaModuleDB *db,
GFile *file);
static PikaModule * pika_module_db_module_find_by_file (PikaModuleDB *db,
GFile *file);
static void pika_module_db_module_dump_func (gpointer data,
gpointer user_data);
static void pika_module_db_list_model_iface_init (GListModelInterface *iface);
G_DEFINE_TYPE_WITH_CODE (PikaModuleDB, pika_module_db, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
pika_module_db_list_model_iface_init))
#define parent_class pika_module_db_parent_class
static void
pika_module_db_class_init (PikaModuleDBClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_module_db_finalize;
}
static void
pika_module_db_init (PikaModuleDB *db)
{
db->modules = g_ptr_array_new ();
db->load_inhibit = NULL;
db->verbose = FALSE;
}
static void
pika_module_db_finalize (GObject *object)
{
PikaModuleDB *db = PIKA_MODULE_DB (object);
g_clear_pointer (&db->modules, g_ptr_array_unref);
g_clear_pointer (&db->load_inhibit, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GType
pika_module_db_get_item_type (GListModel *list)
{
return PIKA_TYPE_MODULE;
}
static guint
pika_module_db_get_n_items (GListModel *list)
{
PikaModuleDB *self = PIKA_MODULE_DB (list);
return self->modules->len;
}
static void *
pika_module_db_get_item (GListModel *list,
guint index)
{
PikaModuleDB *self = PIKA_MODULE_DB (list);
if (index >= self->modules->len)
return NULL;
return g_object_ref (g_ptr_array_index (self->modules, index));
}
static void
pika_module_db_list_model_iface_init (GListModelInterface *iface)
{
iface->get_item_type = pika_module_db_get_item_type;
iface->get_n_items = pika_module_db_get_n_items;
iface->get_item = pika_module_db_get_item;
}
/**
* pika_module_db_new:
* @verbose: Pass %TRUE to enable debugging output.
*
* Creates a new #PikaModuleDB instance. The @verbose parameter will be
* passed to the created #PikaModule instances using pika_module_new().
*
* Returns: The new #PikaModuleDB instance.
**/
PikaModuleDB *
pika_module_db_new (gboolean verbose)
{
PikaModuleDB *db;
db = g_object_new (PIKA_TYPE_MODULE_DB, NULL);
db->verbose = verbose ? TRUE : FALSE;
return db;
}
/**
* pika_module_db_set_verbose:
* @db: A #PikaModuleDB.
* @verbose: the new 'verbose' setting
*
* Sets the 'verbose' setting of @db.
*
* Since: 3.0
**/
void
pika_module_db_set_verbose (PikaModuleDB *db,
gboolean verbose)
{
g_return_if_fail (PIKA_IS_MODULE_DB (db));
db->verbose = verbose ? TRUE : FALSE;
}
/**
* pika_module_db_get_verbose:
* @db: A #PikaModuleDB.
*
* Returns the 'verbose' setting of @db.
*
* Returns: the 'verbose' setting.
*
* Since: 3.0
**/
gboolean
pika_module_db_get_verbose (PikaModuleDB *db)
{
g_return_val_if_fail (PIKA_IS_MODULE_DB (db), FALSE);
return db->verbose;
}
static gboolean
is_in_inhibit_list (GFile *file,
const gchar *inhibit_list)
{
gchar *filename;
gchar *p;
gint pathlen;
const gchar *start;
const gchar *end;
if (! inhibit_list || ! strlen (inhibit_list))
return FALSE;
filename = g_file_get_path (file);
p = strstr (inhibit_list, filename);
if (! p)
{
g_free (filename);
return FALSE;
}
/* we have a substring, but check for colons either side */
start = p;
while (start != inhibit_list && *start != G_SEARCHPATH_SEPARATOR)
start--;
if (*start == G_SEARCHPATH_SEPARATOR)
start++;
end = strchr (p, G_SEARCHPATH_SEPARATOR);
if (! end)
end = inhibit_list + strlen (inhibit_list);
pathlen = strlen (filename);
g_free (filename);
if ((end - start) == pathlen)
return TRUE;
return FALSE;
}
/**
* pika_module_db_set_load_inhibit:
* @db: A #PikaModuleDB.
* @load_inhibit: A #G_SEARCHPATH_SEPARATOR delimited list of module
* filenames to exclude from auto-loading.
*
* Sets the @load_inhibit flag for all #PikaModule's which are kept
* by @db (using pika_module_set_load_inhibit()).
**/
void
pika_module_db_set_load_inhibit (PikaModuleDB *db,
const gchar *load_inhibit)
{
guint i;
g_return_if_fail (PIKA_IS_MODULE_DB (db));
g_free (db->load_inhibit);
db->load_inhibit = g_strdup (load_inhibit);
for (i = 0; i < db->modules->len; i++)
{
PikaModule *module = g_ptr_array_index (db->modules, i);
gboolean inhibit;
inhibit = is_in_inhibit_list (pika_module_get_file (module),
load_inhibit);
pika_module_set_auto_load (module, ! inhibit);
}
}
/**
* pika_module_db_get_load_inhibit:
* @db: A #PikaModuleDB.
*
* Return the #G_SEARCHPATH_SEPARATOR delimited list of module filenames
* which are excluded from auto-loading.
*
* Returns: the @db's @load_inhibit string.
**/
const gchar *
pika_module_db_get_load_inhibit (PikaModuleDB *db)
{
g_return_val_if_fail (PIKA_IS_MODULE_DB (db), NULL);
return db->load_inhibit;
}
/**
* pika_module_db_load:
* @db: A #PikaModuleDB.
* @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
* to load modules from.
*
* Scans the directories contained in @module_path and creates a
* #PikaModule instance for every loadable module contained in the
* directories.
**/
void
pika_module_db_load (PikaModuleDB *db,
const gchar *module_path)
{
g_return_if_fail (PIKA_IS_MODULE_DB (db));
g_return_if_fail (module_path != NULL);
if (g_module_supported ())
{
GList *path;
GList *list;
path = pika_config_path_expand_to_files (module_path, NULL);
for (list = path; list; list = g_list_next (list))
{
pika_module_db_load_directory (db, list->data);
}
g_list_free_full (path, (GDestroyNotify) g_object_unref);
}
if (FALSE)
g_ptr_array_foreach (db->modules, pika_module_db_module_dump_func, NULL);
}
/**
* pika_module_db_refresh:
* @db: A #PikaModuleDB.
* @module_path: A #G_SEARCHPATH_SEPARATOR delimited list of directories
* to load modules from.
*
* Does the same as pika_module_db_load(), plus removes all #PikaModule
* instances whose modules have been deleted from disk.
*
* Note that the #PikaModule's will just be removed from the internal
* list and not freed as this is not possible with #GTypeModule
* instances which actually implement types.
**/
void
pika_module_db_refresh (PikaModuleDB *db,
const gchar *module_path)
{
guint i;
g_return_if_fail (PIKA_IS_MODULE_DB (db));
g_return_if_fail (module_path != NULL);
for (i = 0; i < db->modules->len; i++)
{
PikaModule *module = g_ptr_array_index (db->modules, i);
if (! pika_module_is_on_disk (module) &&
! pika_module_is_loaded (module))
{
g_ptr_array_remove_index (db->modules, i);
g_list_model_items_changed (G_LIST_MODEL (db), i, 1, 0);
i--;
}
}
/* walk filesystem and add new things we find */
pika_module_db_load (db, module_path);
}
static void
pika_module_db_load_directory (PikaModuleDB *db,
GFile *directory)
{
GFileEnumerator *enumerator;
enumerator = g_file_enumerate_children (directory,
G_FILE_ATTRIBUTE_STANDARD_NAME ","
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
G_FILE_ATTRIBUTE_STANDARD_TYPE,
G_FILE_QUERY_INFO_NONE,
NULL, NULL);
if (enumerator)
{
GFileInfo *info;
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
{
GFileType file_type = g_file_info_get_file_type (info);
if (file_type == G_FILE_TYPE_REGULAR &&
! g_file_info_get_is_hidden (info))
{
GFile *child = g_file_enumerator_get_child (enumerator, info);
pika_module_db_load_module (db, child);
g_object_unref (child);
}
g_object_unref (info);
}
g_object_unref (enumerator);
}
}
static void
pika_module_db_load_module (PikaModuleDB *db,
GFile *file)
{
PikaModule *module;
gboolean load_inhibit;
if (! pika_file_has_extension (file, "." G_MODULE_SUFFIX))
return;
/* don't load if we already know about it */
if (pika_module_db_module_find_by_file (db, file))
return;
load_inhibit = is_in_inhibit_list (file, db->load_inhibit);
module = pika_module_new (file,
! load_inhibit,
db->verbose);
g_ptr_array_add (db->modules, module);
g_list_model_items_changed (G_LIST_MODEL (db), db->modules->len - 1, 0, 1);
}
static PikaModule *
pika_module_db_module_find_by_file (PikaModuleDB *db,
GFile *file)
{
guint i;
for (i = 0; i < db->modules->len; i++)
{
PikaModule *module = g_ptr_array_index (db->modules, i);
if (g_file_equal (file, pika_module_get_file (module)))
return module;
}
return NULL;
}
static void
pika_module_db_module_dump_func (gpointer data,
gpointer user_data)
{
static const gchar * const statenames[] =
{
N_("Module error"),
N_("Loaded"),
N_("Load failed"),
N_("Not loaded")
};
PikaModule *module = data;
const PikaModuleInfo *info = pika_module_get_info (module);
g_print ("\n%s: %s\n",
pika_file_get_utf8_name (pika_module_get_file (module)),
gettext (statenames[pika_module_get_state (module)]));
#if 0
g_print (" module: %p lasterr: %s query: %p register: %p\n",
module->module,
module->last_module_error ? module->last_module_error : "NONE",
module->query_module,
module->register_module);
#endif
if (info)
{
g_print (" purpose: %s\n"
" author: %s\n"
" version: %s\n"
" copyright: %s\n"
" date: %s\n",
info->purpose ? info->purpose : "NONE",
info->author ? info->author : "NONE",
info->version ? info->version : "NONE",
info->copyright ? info->copyright : "NONE",
info->date ? info->date : "NONE");
}
}

View File

@ -0,0 +1,50 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* 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/>.
*/
#if !defined (__PIKA_MODULE_H_INSIDE__) && !defined (PIKA_MODULE_COMPILATION)
#error "Only <libpikamodule/pikamodule.h> can be included directly."
#endif
#ifndef __PIKA_MODULE_DB_H__
#define __PIKA_MODULE_DB_H__
G_BEGIN_DECLS
#define PIKA_TYPE_MODULE_DB (pika_module_db_get_type ())
G_DECLARE_FINAL_TYPE (PikaModuleDB, pika_module_db, PIKA, MODULE_DB, GObject)
PikaModuleDB * pika_module_db_new (gboolean verbose);
void pika_module_db_set_verbose (PikaModuleDB *db,
gboolean verbose);
gboolean pika_module_db_get_verbose (PikaModuleDB *db);
void pika_module_db_set_load_inhibit (PikaModuleDB *db,
const gchar *load_inhibit);
const gchar * pika_module_db_get_load_inhibit (PikaModuleDB *db);
void pika_module_db_load (PikaModuleDB *db,
const gchar *module_path);
void pika_module_db_refresh (PikaModuleDB *db,
const gchar *module_path);
G_END_DECLS
#endif /* __PIKA_MODULE_DB_H__ */

View File

@ -0,0 +1,38 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* 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
* Library 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/>.
*/
#ifndef __PIKA_MODULE_TYPES_H__
#define __PIKA_MODULE_TYPES_H__
#include <libpikabase/pikabasetypes.h>
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
typedef struct _PikaModule PikaModule;
typedef struct _PikaModuleInfo PikaModuleInfo;
typedef struct _PikaModuleDB PikaModuleDB;
G_END_DECLS
#endif /* __PIKA_MODULE_TYPES_H__ */