32 #include <sys/types.h> 37 #include "gnc-module.h" 39 static GHashTable * loaded_modules = NULL;
40 static GList * module_info = NULL;
45 char * module_description;
46 char * module_filepath;
58 int (* init_func)(
int refcount);
61 static GNCModuleInfo * gnc_module_get_info(
const char * lib_path);
69 gnc_module_system_search_dirs(
void)
71 const char *spath = g_getenv(
"GNC_MODULE_PATH");
73 GString * token = g_string_new(NULL);
79 spath = DEFAULT_MODULE_PATH;
82 for (cpos = spath; *cpos; cpos++)
100 g_string_append_c(token, *cpos);
107 case G_SEARCHPATH_SEPARATOR:
110 char *token_str = g_string_free (token, FALSE);
111 list = g_list_append (list, token_str);
112 token = g_string_new(NULL);
116 g_string_append_c(token, *cpos);
122 g_string_append_c(token, *cpos);
129 char *token_str = g_string_free (token, FALSE);
130 list = g_list_append(list, token_str);
134 g_string_free(token, TRUE);
144 gnc_module_system_init(
void)
149 loaded_modules = g_hash_table_new(g_direct_hash, g_direct_equal);
152 gnc_module_system_refresh();
155 static inline gboolean
156 exclude_module (
const char* module)
163 static const char* excluded_modules[] =
165 "libgncmod-app-utils",
166 "libgncmod-bi-import",
167 "libgncmod-csv-export",
168 "libgncmod-csv-import",
169 "libgncmod-customer-import",
171 "libgncmod-generic-import",
172 "libgncmod-gnome-search",
173 "libgncmod-gnome-utils",
175 "libgncmod-ledger-core",
176 "libgncmod-locale-reports-us",
177 "libgncmod-log-replay",
178 "libgncmod-qif-import",
179 "libgncmod-register-core",
180 "libgncmod-register-gnome",
181 "libgncmod-report-gnome",
182 "libgncmod-report-system",
183 "libgncmod-stylesheets",
186 static const unsigned len = G_N_ELEMENTS (excluded_modules);
187 unsigned namelen = strchr(module,
'.') ?
188 strchr(module,
'.') - module : strlen (module);
189 for (
unsigned i = 0; i < len; ++i)
190 if (strncmp(excluded_modules[i], module, MIN(namelen, strlen(excluded_modules[i]))) == 0)
202 gnc_module_system_refresh(
void)
209 gnc_module_system_init();
213 search_dirs = gnc_module_system_search_dirs();
216 for (current = search_dirs; current; current = current->next)
218 GDir *d = g_dir_open(current->data, 0, NULL);
219 const gchar *dent = NULL;
220 char * fullpath = NULL;
225 while ((dent = g_dir_read_name(d)) != NULL)
238 if ((g_str_has_suffix(dent,
"." G_MODULE_SUFFIX)
239 || g_str_has_suffix(dent,
".dylib"))
240 && g_str_has_prefix(dent, GNC_MODULE_PREFIX)
241 && !exclude_module(dent))
245 fullpath = g_build_filename((
const gchar *)(current->data),
247 info = gnc_module_get_info(fullpath);
251 module_info = g_list_prepend(module_info, info);
260 g_list_free_full (search_dirs, g_free);
270 gnc_module_system_modinfo(
void)
274 gnc_module_system_init();
286 gnc_module_get_symbol(GModule* gmodule,
const char* symbol, gpointer res)
289 gchar* munged_symbol;
293 g_return_val_if_fail(gmodule, FALSE);
294 g_return_val_if_fail(symbol, FALSE);
299 basename = g_path_get_basename(g_module_name(gmodule));
300 strs = g_strsplit(basename,
".", 2);
304 g_strdelimit(strs[0],
"-",
'_');
307 munged_symbol = g_strdup_printf(
"%s_%s", strs[0], symbol);
308 ret = g_module_symbol(gmodule, munged_symbol, res);
314 g_free(munged_symbol);
325 gnc_module_get_info(
const char * fullpath)
330 gpointer initfunc, pathfunc, descripfunc, iface, revision, age;
331 gchar * (* f_path)(void);
332 gchar * (* f_descrip)(void);
335 gmodule = g_module_open(fullpath, G_MODULE_BIND_LAZY);
338 g_debug(
"Failed to dlopen() '%s': %s\n", fullpath, g_module_error());
344 if (!gnc_module_get_symbol(gmodule,
"gnc_module_system_interface", &modsysver))
351 if (*(
int *)modsysver != 0)
353 g_warning(
"Module '%s' requires newer module system\n", fullpath);
357 if (!gnc_module_get_symbol(gmodule,
"gnc_module_init", &initfunc) ||
358 !gnc_module_get_symbol(gmodule,
"gnc_module_path", &pathfunc) ||
359 !gnc_module_get_symbol(gmodule,
"gnc_module_description", &descripfunc) ||
360 !gnc_module_get_symbol(gmodule,
"gnc_module_current", &iface) ||
361 !gnc_module_get_symbol(gmodule,
"gnc_module_revision", &revision) ||
362 !gnc_module_get_symbol(gmodule,
"gnc_module_age", &age))
364 g_warning(
"Module '%s' does not match module signature\n", fullpath);
371 f_descrip = descripfunc;
372 info->module_path = f_path();
373 info->module_description = f_descrip();
374 info->module_filepath = g_strdup(fullpath);
375 info->module_interface = *(
int *)iface;
376 info->module_age = *(
int *)age;
377 info->module_revision = *(
int *)revision;
379 g_module_make_resident(gmodule);
382 g_module_close(gmodule);
394 gnc_module_locate(
const gchar * module_name,
int iface)
402 gnc_module_system_init();
405 for (lptr = module_info; lptr; lptr = lptr->next)
407 current = lptr->data;
408 if (!strcmp(module_name, current->module_path) &&
409 (iface >= (current->module_interface - current->module_age)) &&
410 (iface <= current->module_interface))
414 if ((current->module_interface > best->module_interface) ||
415 ((current->module_interface == best->module_interface) &&
416 (current->module_age > best->module_age)) ||
417 ((current->module_interface == best->module_interface) &&
418 (current->module_age == best->module_age) &&
419 (current->module_revision > best->module_revision)))
434 list_loaded (gpointer k, gpointer v, gpointer data)
437 *l = g_list_prepend(*l, v);
441 gnc_module_check_loaded(
const char * module_name, gint iface)
443 GNCModuleInfo * modinfo = gnc_module_locate(module_name, iface);
444 GList * modules = NULL;
455 gnc_module_system_init();
459 g_hash_table_foreach(loaded_modules, list_loaded, &modules);
462 for (p = modules; p; p = p->next)
465 if (!strcmp(lm->filename, modinfo->module_filepath))
471 g_list_free(modules);
482 gnc_module_load_common(
const char * module_name, gint iface, gboolean optional)
489 g_debug (
"module_name: %s", module_name);
493 gnc_module_system_init();
496 info = gnc_module_check_loaded(module_name, iface);
508 if (info->init_func(info->load_count))
511 g_debug (
"module %s already loaded", module_name);
516 g_warning (
"module init failed: %s", module_name);
522 g_warning (
"module has no init func: %s", module_name);
526 g_error(
"internal error");
530 modinfo = gnc_module_locate(module_name, iface);
535 g_message (
"Could not locate optional module %s interface v.%d",
540 g_warning (
"Could not locate module %s interface v.%d",
550 if ((gmodule = g_module_open(modinfo->module_filepath, 0)) != NULL)
554 if (gnc_module_get_symbol(gmodule,
"gnc_module_init", &initfunc))
558 info->gmodule = gmodule;
559 info->filename = g_strdup(modinfo->module_filepath);
560 info->load_count = 1;
561 info->init_func = initfunc;
562 g_hash_table_insert(loaded_modules, info, info);
566 if (!info->init_func(0))
569 g_warning (
"Initialization failed for module %s", module_name);
570 g_hash_table_remove(loaded_modules, info);
571 g_free(info->filename);
581 g_warning (
"Module %s (%s) is not a gnc-module.\n", module_name,
582 modinfo->module_filepath);
588 g_warning (
"Failed to open module %s: %s\n", module_name, g_module_error());
595 gnc_module_load(
const char * module_name, gint iface)
597 return gnc_module_load_common(module_name, iface, FALSE);
601 gnc_module_load_optional(
const char * module_name, gint iface)
603 return gnc_module_load_common(module_name, iface, TRUE);
612 gnc_module_unload(GNCModule module)
618 gnc_module_system_init();
621 if ((info = g_hash_table_lookup(loaded_modules, module)) != NULL)
623 gpointer unload_thunk;
624 int unload_val = TRUE;
627 if (gnc_module_get_symbol(info->gmodule,
"gnc_module_end", &unload_thunk))
629 int (* thunk)(int) = unload_thunk;
630 unload_val = thunk(info->load_count);
634 if (info->load_count == 0)
639 g_hash_table_remove(loaded_modules, module);
646 g_warning (
"Failed to unload module %p (it is not loaded)\n", module);