trunk: changeset 1972
[notion/jeffpc.git] / ioncore / modules.c
bloba363dcb2732e368e9fa35ba9f07d546fec7e398e
1 /*
2 * ion/ioncore/modules.c
4 * Copyright (c) Tuomo Valkonen 1999-2005.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
12 #include <string.h>
13 #include <ctype.h>
14 #include <dlfcn.h>
15 #include <unistd.h>
17 #include <libtu/rb.h>
18 #include <libextl/readconfig.h>
20 #include "common.h"
21 #include "modules.h"
22 #include "../version.h"
25 #ifndef CF_PRELOAD_MODULES
28 /*{{{ Module list */
31 typedef void *dlhandle;
34 static Rb_node modules=NULL;
37 static dlhandle get_handle(const char *name)
39 int found=0;
40 Rb_node nd;
42 nd=rb_find_key_n(modules, name, &found);
43 if(found)
44 return nd->v.val;
45 return NULL;
49 static const char *get_name(dlhandle handle)
51 Rb_node nd;
53 rb_traverse(nd, modules){
54 if(nd->v.val==handle)
55 return (const char *)(nd->k.key);
57 return NULL;
61 static Rb_node add_module(char *name, dlhandle handle)
63 return rb_insert(modules, name, handle);
67 /*}}}*/
70 /*{{{ Module symbol access */
73 static void *get_module_symbol(dlhandle handle,
74 const char *modulename,
75 const char *name)
77 char *p;
78 void *ret;
80 p=scat(modulename, name);
82 if(p==NULL)
83 return NULL;
85 ret=dlsym(handle, p);
87 free(p);
89 return ret;
92 static bool check_version(dlhandle handle, const char *modulename)
94 char *versionstr=(char*)get_module_symbol(handle, modulename,
95 "_ion_api_version");
96 if(versionstr==NULL)
97 return FALSE;
98 return (strcmp(versionstr, ION_API_VERSION)==0);
102 static bool call_init(dlhandle handle, const char *modulename)
104 bool (*initfn)(void);
106 initfn=(bool (*)())get_module_symbol(handle, modulename, "_init");
108 if(initfn==NULL)
109 return TRUE;
111 return initfn();
115 static void call_deinit(dlhandle handle, const char *modulename)
117 void (*deinitfn)(void);
119 deinitfn=(void (*)())get_module_symbol(handle, modulename, "_deinit");
121 if(deinitfn!=NULL)
122 deinitfn();
126 /*}}}*/
129 /*{{{ Init */
132 bool ioncore_init_module_support()
134 modules=make_rb();
135 return (modules!=NULL);
139 static int try_load(const char *file, void *param)
141 dlhandle handle=NULL;
142 const char *slash, *dot;
143 char *name;
144 Rb_node mod;
146 if(access(file, F_OK)!=0)
147 return EXTL_TRYCONFIG_NOTFOUND;
149 slash=strrchr(file, '/');
150 dot=strrchr(file, '.');
152 if(slash==NULL)
153 slash=file;
154 else
155 slash++;
157 if(dot<=slash){
158 warn(TR("Invalid module name."));
159 goto err1;
162 name=ALLOC_N(char, dot-slash+1);
163 if(name==NULL)
164 goto err1;
166 strncpy(name, slash, dot-slash);
167 name[dot-slash]='\0';
169 if(get_handle(name)){
170 warn_obj(file, TR("The module is already loaded."));
171 goto err2;
174 handle=dlopen(file, RTLD_NOW|RTLD_GLOBAL);
176 if(handle==NULL){
177 warn_obj(file, "%s", dlerror());
178 goto err2;
181 if(get_name(handle))
182 return EXTL_TRYCONFIG_OK;
184 if(!check_version(handle, name)){
185 warn_obj(file, TR("Module version information not found or "
186 "version mismatch. Refusing to use."));
187 goto err3;
190 mod=add_module(name, handle);
192 if(mod==NULL)
193 goto err3;
195 if(!call_init(handle, name)){
196 warn_obj(file, TR("Unable to initialise module %s."), name);
197 rb_delete_node(mod);
198 goto err3;
201 return EXTL_TRYCONFIG_OK;
203 err3:
204 dlclose(handle);
205 err2:
206 free(name);
207 err1:
208 return EXTL_TRYCONFIG_LOAD_FAILED;
212 static bool do_load_module(const char *modname)
214 int retval;
216 retval=extl_try_config(modname, NULL, (ExtlTryConfigFn*)try_load,
217 NULL, "so", NULL);
219 if(retval==EXTL_TRYCONFIG_NOTFOUND)
220 warn(TR("Unable to find '%s' on search path."), modname);
222 return (retval==EXTL_TRYCONFIG_OK);
226 /*}}}*/
229 /*{{{ Deinit */
232 static void do_unload_module(Rb_node mod)
234 char *name=(char*)mod->k.key;
235 dlhandle handle=mod->v.val;
237 call_deinit(handle, name);
239 dlclose(handle);
240 free(name);
244 void ioncore_unload_modules()
246 Rb_node mod;
248 rb_traverse(mod, modules){
249 do_unload_module(mod);
254 /*}}}*/
257 #else
260 /*{{{ Static module support */
263 static bool call_init(WStaticModuleInfo *handle)
265 if(handle->init!=NULL)
266 return handle->init();
267 return TRUE;
271 static void call_deinit(WStaticModuleInfo *handle)
273 if(handle->deinit!=NULL)
274 handle->deinit();
278 extern WStaticModuleInfo ioncore_static_modules[];
281 static bool do_load_module(const char *name)
283 WStaticModuleInfo *mod;
285 for(mod=ioncore_static_modules; mod->name!=NULL; mod++){
286 if(strcmp(mod->name, name)==0)
287 break;
290 if(mod->name==NULL){
291 warn_obj(name, TR("Unknown module."));
292 return FALSE;
295 if(mod->loaded)
296 return TRUE;
298 if(!call_init(mod)){
299 warn_obj(name, TR("Unable to initialise module."));
300 return FALSE;
303 mod->loaded=TRUE;
305 return TRUE;
309 void ioncore_unload_modules()
311 WStaticModuleInfo *mod;
313 for(mod=ioncore_static_modules; mod->name!=NULL; mod++){
314 if(mod->loaded){
315 call_deinit(mod);
316 mod->loaded=FALSE;
322 bool ioncore_init_module_support()
324 return TRUE;
328 /*}}}*/
331 #endif
334 /*{{{ Exports */
337 /*EXTL_DOC
338 * Attempt to load a C-side module.
340 EXTL_EXPORT
341 bool ioncore_load_module(const char *modname)
343 if(modname==NULL){
344 warn(TR("No module to load given."));
345 return FALSE;
347 return do_load_module(modname);
351 /*}}}*/