12 #include <sys/types.h>
17 #include "gnc-module.h"
18 #include "libqof/qof/qof.h"
23 static GHashTable * loaded_modules = NULL;
24 static GList * module_info = NULL;
29 char * module_description;
30 char * module_filepath;
42 int (* init_func)(
int refcount);
45 static GNCModuleInfo * gnc_module_get_info(
const char * lib_path);
53 gnc_module_system_search_dirs(
void)
55 const char *spath = g_getenv(
"GNC_MODULE_PATH");
57 GString * token = g_string_new(NULL);
63 spath = DEFAULT_MODULE_PATH;
66 for (cpos = spath; *cpos; cpos++)
84 g_string_append_c(token, *cpos);
91 case G_SEARCHPATH_SEPARATOR:
94 list = g_list_append(list, token->str);
95 g_string_free(token, FALSE);
96 token = g_string_new(NULL);
100 g_string_append_c(token, *cpos);
106 g_string_append_c(token, *cpos);
113 list = g_list_append(list, token->str);
114 g_string_free(token, FALSE);
118 g_string_free(token, TRUE);
129 gnc_module_system_init(
void)
134 loaded_modules = g_hash_table_new(g_direct_hash, g_direct_equal);
137 gnc_module_system_refresh();
148 gnc_module_system_refresh(
void)
155 gnc_module_system_init();
159 search_dirs = gnc_module_system_search_dirs();
162 for (current = search_dirs; current; current = current->next)
164 GDir *d = g_dir_open(current->data, 0, NULL);
165 const gchar *dent = NULL;
166 char * fullpath = NULL;
171 while ((dent = g_dir_read_name(d)) != NULL)
184 if ((g_str_has_suffix(dent,
"." G_MODULE_SUFFIX)
185 || g_str_has_suffix(dent,
".dylib"))
186 && g_str_has_prefix(dent, GNC_MODULE_PREFIX))
190 fullpath = g_build_filename((
const gchar *)(current->data),
192 info = gnc_module_get_info(fullpath);
196 module_info = g_list_prepend(module_info, info);
205 for (current = search_dirs; current; current = current->next)
207 g_free(current->data);
209 g_list_free(current);
219 gnc_module_system_modinfo(
void)
223 gnc_module_system_init();
235 gnc_module_get_symbol(GModule* gmodule,
const char* symbol, gpointer res)
238 gchar* munged_symbol;
242 g_return_val_if_fail(gmodule, FALSE);
243 g_return_val_if_fail(symbol, FALSE);
248 basename = g_path_get_basename(g_module_name(gmodule));
249 strs = g_strsplit(basename,
".", 2);
253 g_strdelimit(strs[0],
"-",
'_');
256 munged_symbol = g_strdup_printf(
"%s_%s", strs[0], symbol);
257 ret = g_module_symbol(gmodule, munged_symbol, res);
263 g_free(munged_symbol);
274 gnc_module_get_info(
const char * fullpath)
279 gpointer initfunc, pathfunc, descripfunc, iface, revision, age;
280 gchar * (* f_path)(void);
281 gchar * (* f_descrip)(void);
284 gmodule = g_module_open(fullpath, G_MODULE_BIND_LAZY);
287 g_warning(
"Failed to dlopen() '%s': %s\n", fullpath, g_module_error());
293 if (!gnc_module_get_symbol(gmodule,
"gnc_module_system_interface", &modsysver))
300 if (*(
int *)modsysver != 0)
302 g_warning(
"Module '%s' requires newer module system\n", fullpath);
306 if (!gnc_module_get_symbol(gmodule,
"gnc_module_init", &initfunc) ||
307 !gnc_module_get_symbol(gmodule,
"gnc_module_path", &pathfunc) ||
308 !gnc_module_get_symbol(gmodule,
"gnc_module_description", &descripfunc) ||
309 !gnc_module_get_symbol(gmodule,
"gnc_module_current", &iface) ||
310 !gnc_module_get_symbol(gmodule,
"gnc_module_revision", &revision) ||
311 !gnc_module_get_symbol(gmodule,
"gnc_module_age", &age))
313 g_warning(
"Module '%s' does not match module signature\n", fullpath);
320 f_descrip = descripfunc;
321 info->module_path = f_path();
322 info->module_description = f_descrip();
323 info->module_filepath = g_strdup(fullpath);
324 info->module_interface = *(
int *)iface;
325 info->module_age = *(
int *)age;
326 info->module_revision = *(
int *)revision;
328 g_module_make_resident(gmodule);
331 g_module_close(gmodule);
343 gnc_module_locate(
const gchar * module_name,
int iface)
351 gnc_module_system_init();
354 for (lptr = module_info; lptr; lptr = lptr->next)
356 current = lptr->data;
357 if (!strcmp(module_name, current->module_path) &&
358 (iface >= (current->module_interface - current->module_age)) &&
359 (iface <= current->module_interface))
363 if ((current->module_interface > best->module_interface) ||
364 ((current->module_interface == best->module_interface) &&
365 (current->module_age > best->module_age)) ||
366 ((current->module_interface == best->module_interface) &&
367 (current->module_age == best->module_age) &&
368 (current->module_revision > best->module_revision)))
383 list_loaded (gpointer k, gpointer v, gpointer data)
386 *l = g_list_prepend(*l, v);
390 gnc_module_check_loaded(
const char * module_name, gint iface)
392 GNCModuleInfo * modinfo = gnc_module_locate(module_name, iface);
393 GList * modules = NULL;
404 gnc_module_system_init();
408 g_hash_table_foreach(loaded_modules, list_loaded, &modules);
411 for (p = modules; p; p = p->next)
414 if (!strcmp(lm->filename, modinfo->module_filepath))
420 g_list_free(modules);
431 gnc_module_load_common(
const char * module_name, gint iface, gboolean optional)
438 ENTER(
"module_name: %s", module_name);
442 gnc_module_system_init();
445 info = gnc_module_check_loaded(module_name, iface);
457 if (info->init_func(info->load_count))
460 LEAVE(
"module %s already loaded", module_name);
465 g_warning (
"module init failed: %s", module_name);
472 g_warning (
"module has no init func: %s", module_name);
477 g_error(
"internal error");
482 modinfo = gnc_module_locate(module_name, iface);
487 g_message (
"Could not locate optional module %s interface v.%d",
492 g_warning (
"Could not locate module %s interface v.%d",
503 if ((gmodule = g_module_open(modinfo->module_filepath, 0)) != NULL)
507 if (gnc_module_get_symbol(gmodule,
"gnc_module_init", &initfunc))
511 info->gmodule = gmodule;
512 info->filename = g_strdup(modinfo->module_filepath);
513 info->load_count = 1;
514 info->init_func = initfunc;
515 g_hash_table_insert(loaded_modules, info, info);
519 if (!info->init_func(0))
522 g_warning (
"Initialization failed for module %s\n", module_name);
523 g_hash_table_remove(loaded_modules, info);
524 g_free(info->filename);
536 g_warning (
"Module %s (%s) is not a gnc-module.\n", module_name,
537 modinfo->module_filepath);
544 g_warning (
"Failed to open module %s: %s\n", module_name, g_module_error());
552 gnc_module_load(
const char * module_name, gint iface)
554 return gnc_module_load_common(module_name, iface, FALSE);
558 gnc_module_load_optional(
const char * module_name, gint iface)
560 return gnc_module_load_common(module_name, iface, TRUE);
569 gnc_module_unload(GNCModule module)
575 gnc_module_system_init();
578 if ((info = g_hash_table_lookup(loaded_modules, module)) != NULL)
580 gpointer unload_thunk;
581 int unload_val = TRUE;
584 if (gnc_module_get_symbol(info->gmodule,
"gnc_module_end", &unload_thunk))
586 int (* thunk)(int) = unload_thunk;
587 unload_val = thunk(info->load_count);
591 if (info->load_count == 0)
596 g_hash_table_remove(loaded_modules, module);
603 g_warning (
"Failed to unload module %p (it is not loaded)\n", module);
#define ENTER(format, args...)
#define LEAVE(format, args...)
const gchar * QofLogModule