4 Copyright (C) 1999-2000 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 static GHashTable *uniqids, *uniqstrids;
31 static GHashTable *idlookup, *stridlookup;
32 static int next_uniq_id;
34 void *module_check_cast(void *object, int type_pos, const char *id)
36 return object == NULL || module_find_id(id,
37 G_STRUCT_MEMBER(int, object, type_pos)) == -1 ? NULL : object;
40 void *module_check_cast_module(void *object, int type_pos,
41 const char *module, const char *id)
48 str = module_find_id_str(module,
49 G_STRUCT_MEMBER(int, object, type_pos));
50 return str == NULL || strcmp(str, id) != 0 ? NULL : object;
53 /* return unique number across all modules for `id' */
54 int module_get_uniq_id(const char *module, int id)
57 gpointer origkey, uniqid, idp;
60 g_return_val_if_fail(module != NULL, -1);
62 ids = g_hash_table_lookup(idlookup, module);
65 ids = g_hash_table_new((GHashFunc) g_direct_hash,
66 (GCompareFunc) g_direct_equal);
67 g_hash_table_insert(idlookup, g_strdup(module), ids);
70 idp = GINT_TO_POINTER(id);
71 if (!g_hash_table_lookup_extended(ids, idp, &origkey, &uniqid)) {
74 g_hash_table_insert(ids, idp, GINT_TO_POINTER(ret));
75 g_hash_table_insert(uniqids, GINT_TO_POINTER(ret), idp);
77 ret = GPOINTER_TO_INT(uniqid);
83 /* return unique number across all modules for `id' */
84 int module_get_uniq_id_str(const char *module, const char *id)
87 gpointer origkey, uniqid;
90 g_return_val_if_fail(module != NULL, -1);
92 ids = g_hash_table_lookup(stridlookup, module);
95 ids = g_hash_table_new((GHashFunc) g_str_hash,
96 (GCompareFunc) g_str_equal);
97 g_hash_table_insert(stridlookup, g_strdup(module), ids);
100 if (!g_hash_table_lookup_extended(ids, id, &origkey, &uniqid)) {
104 saveid = g_strdup(id);
105 ret = next_uniq_id++;
106 g_hash_table_insert(ids, saveid, GINT_TO_POINTER(ret));
107 g_hash_table_insert(uniqstrids, GINT_TO_POINTER(ret), saveid);
109 ret = GPOINTER_TO_INT(uniqid);
115 /* returns the original module specific id, -1 = not found */
116 int module_find_id(const char *module, int uniqid)
119 gpointer origkey, id;
122 g_return_val_if_fail(module != NULL, -1);
124 if (!g_hash_table_lookup_extended(uniqids, GINT_TO_POINTER(uniqid),
128 /* check that module matches */
129 idlist = g_hash_table_lookup(idlookup, module);
133 ret = GPOINTER_TO_INT(id);
134 if (!g_hash_table_lookup_extended(idlist, id, &origkey, &id) ||
135 GPOINTER_TO_INT(id) != uniqid)
141 /* returns the original module specific id, NULL = not found */
142 const char *module_find_id_str(const char *module, int uniqid)
145 gpointer origkey, id;
148 g_return_val_if_fail(module != NULL, NULL);
150 if (!g_hash_table_lookup_extended(uniqstrids, GINT_TO_POINTER(uniqid),
154 /* check that module matches */
155 idlist = g_hash_table_lookup(stridlookup, module);
160 if (!g_hash_table_lookup_extended(idlist, id, &origkey, &id) ||
161 GPOINTER_TO_INT(id) != uniqid)
167 static void uniq_destroy(gpointer key, gpointer value)
169 g_hash_table_remove(uniqids, value);
172 static void uniq_destroy_str(gpointer key, gpointer value)
174 g_hash_table_remove(uniqstrids, value);
178 /* Destroy unique IDs from `module'. This function is automatically called
179 when module is destroyed with module's name as the parameter. */
180 void module_uniq_destroy(const char *module)
185 if (g_hash_table_lookup_extended(idlookup, module, &key,
186 (gpointer *) &idlist)) {
187 g_hash_table_remove(idlookup, key);
190 g_hash_table_foreach(idlist, (GHFunc) uniq_destroy, NULL);
191 g_hash_table_destroy(idlist);
194 if (g_hash_table_lookup_extended(stridlookup, module, &key,
195 (gpointer *) &idlist)) {
196 g_hash_table_remove(stridlookup, key);
199 g_hash_table_foreach(idlist, (GHFunc) uniq_destroy_str, NULL);
200 g_hash_table_destroy(idlist);
204 MODULE_REC *module_find(const char *name)
208 for (tmp = modules; tmp != NULL; tmp = tmp->next) {
209 MODULE_REC *rec = tmp->data;
211 if (g_strcasecmp(rec->name, name) == 0)
219 static char *module_get_name(const char *path, int *start, int *end)
222 char *module_name, *ptr;
225 if (g_path_is_absolute(path)) {
226 name = strrchr(path, G_DIR_SEPARATOR);
227 if (name != NULL) name++;
233 if (strncmp(name, "lib", 3) == 0)
236 module_name = g_strdup(name);
237 ptr = strchr(module_name, '.');
238 if (ptr != NULL) *ptr = '\0';
240 *start = (int) (name-path);
241 *end = *start + (ptr == NULL ? strlen(name) :
242 (int) (module_name-ptr));
247 static GModule *module_open(const char *name)
253 if (g_path_is_absolute(name) ||
254 (*name == '.' && name[1] == G_DIR_SEPARATOR))
255 path = g_strdup(name);
257 /* first try from home dir */
258 str = g_strdup_printf("%s/.silc/modules", g_get_home_dir());
259 path = g_module_build_path(str, name);
262 if (stat(path, &statbuf) == 0) {
263 module = g_module_open(path, (GModuleFlags) 0);
268 /* module not found from home dir, try global module dir */
270 path = g_module_build_path(MODULEDIR, name);
273 module = g_module_open(path, (GModuleFlags) 0);
278 #define module_error(error, module, text) \
279 signal_emit("module error", 3, GINT_TO_POINTER(error), module, text)
281 static int module_load_name(const char *path, const char *name, int silent)
283 void (*module_init) (void);
288 gmodule = module_open(path);
289 if (gmodule == NULL) {
291 module_error(MODULE_ERROR_LOAD, name,
297 /* get the module's init() function */
298 initfunc = g_strconcat(name, "_init", NULL);
299 if (!g_module_symbol(gmodule, initfunc, (gpointer *) &module_init)) {
301 module_error(MODULE_ERROR_INVALID, name, NULL);
302 g_module_close(gmodule);
308 rec = g_new0(MODULE_REC, 1);
309 rec->name = g_strdup(name);
310 rec->gmodule = gmodule;
311 modules = g_slist_append(modules, rec);
314 settings_check_module(name);
316 signal_emit("module loaded", 1, rec);
321 /* Load module - automatically tries to load also the related non-core
322 modules given in `prefixes' (like irc, fe, fe_text, ..) */
323 int module_load(const char *path, char **prefixes)
330 g_return_val_if_fail(path != NULL, FALSE);
332 if (!g_module_supported())
335 name = module_get_name(path, &start, &end);
336 if (module_find(name)) {
337 module_error(MODULE_ERROR_ALREADY_LOADED, name, NULL);
342 /* load "module_core" instead of "module" if it exists */
343 realpath = g_string_new(path);
344 g_string_insert(realpath, end, "_core");
346 pname = g_strconcat(name, "_core", NULL);
347 ret = module_load_name(realpath->str, pname, TRUE);
351 /* load "module" - complain if it's not found */
352 ret = module_load_name(path, name, FALSE);
353 } else if (prefixes != NULL) {
354 /* load all the "prefix modules", like the fe-common, irc,
355 etc. part of the module */
356 while (*prefixes != NULL) {
357 g_string_assign(realpath, path);
358 g_string_insert(realpath, start, "_");
359 g_string_insert(realpath, start, *prefixes);
361 pname = g_strconcat(*prefixes, "_", name, NULL);
362 module_load_name(realpath->str, pname, TRUE);
369 g_string_free(realpath, TRUE);
377 void module_unload(MODULE_REC *module)
380 void (*module_deinit) (void);
383 g_return_if_fail(module != NULL);
385 modules = g_slist_remove(modules, module);
387 signal_emit("module unloaded", 1, module);
389 /* call the module's deinit() function */
390 deinitfunc = g_strconcat(module->name, "_deinit", NULL);
391 if (g_module_symbol(module->gmodule, deinitfunc,
392 (gpointer *) &module_deinit))
396 settings_remove_module(module->name);
397 commands_remove_module(module->name);
398 signals_remove_module(module->name);
400 g_module_close(module->gmodule);
401 g_free(module->name);
406 static void uniq_get_modules(char *key, void *value, GSList **list)
408 *list = g_slist_append(*list, key);
411 void modules_init(void)
415 idlookup = g_hash_table_new((GHashFunc) g_str_hash,
416 (GCompareFunc) g_str_equal);
417 uniqids = g_hash_table_new((GHashFunc) g_direct_hash,
418 (GCompareFunc) g_direct_equal);
420 stridlookup = g_hash_table_new((GHashFunc) g_str_hash,
421 (GCompareFunc) g_str_equal);
422 uniqstrids = g_hash_table_new((GHashFunc) g_direct_hash,
423 (GCompareFunc) g_direct_equal);
427 void modules_deinit(void)
432 g_hash_table_foreach(idlookup, (GHFunc) uniq_get_modules, &list);
433 g_hash_table_foreach(stridlookup, (GHFunc) uniq_get_modules, &list);
435 while (list != NULL) {
436 module_uniq_destroy(list->data);
437 list = g_slist_remove(list, list->data);
440 g_hash_table_destroy(idlookup);
441 g_hash_table_destroy(stridlookup);
442 g_hash_table_destroy(uniqids);
443 g_hash_table_destroy(uniqstrids);