Fix:Core:Further cleanups
[navit-package] / navit / plugin.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <string.h>
21 #include <glib.h>
22 #include "config.h"
23 #ifdef USE_PLUGINS
24 #ifdef HAVE_GMODULE
25 #include <gmodule.h>
26 #else
27 #include <dlfcn.h>
28 #endif
29 #endif
30 #include "plugin.h"
31 #include "file.h"
32 #define PLUGIN_C
33 #include "plugin.h"
34 #include "item.h"
35 #include "debug.h"
36
37 #ifdef USE_PLUGINS
38 #ifndef HAVE_GMODULE
39 typedef void * GModule;
40 #define G_MODULE_BIND_LOCAL 1
41 #define G_MODULE_BIND_LAZY 2
42 static int
43 g_module_supported(void)
44 {
45         return 1;
46 }
47
48 static void *
49 g_module_open(char *name, int flags)
50 {
51         return dlopen(name,
52                 (flags & G_MODULE_BIND_LAZY ? RTLD_LAZY : RTLD_NOW) |
53                 (flags & G_MODULE_BIND_LOCAL ? RTLD_LOCAL : RTLD_GLOBAL));
54 }
55
56 static char *
57 g_module_error(void)
58 {
59         return dlerror();
60 }
61
62 static int
63 g_module_symbol(GModule *handle, char *symbol, gpointer *addr)
64 {
65         *addr=dlsym(handle, symbol);
66         return (*addr != NULL);
67 }
68
69 static void
70 g_module_close(GModule *handle)
71 {
72         dlclose(handle);
73 }
74
75 #endif
76 #endif
77
78 struct plugin {
79         int active;
80         int lazy;
81         int ondemand;
82         char *name;
83 #ifdef USE_PLUGINS
84         GModule *mod;
85 #endif
86         void (*init)(void);
87 };
88
89 struct plugins {
90         GHashTable *hash;
91         GList *list;
92 } *pls;
93
94 static struct plugin *
95 plugin_new_from_path(char *plugin)
96 {
97 #ifdef USE_PLUGINS
98         struct plugin *ret;
99         if (! g_module_supported()) {
100                return NULL;
101         }
102         ret=g_new0(struct plugin, 1);
103         ret->name=g_strdup(plugin);
104         return ret;
105 #else
106         return NULL;
107 #endif
108 }
109
110 int
111 plugin_load(struct plugin *pl)
112 {
113 #ifdef USE_PLUGINS
114         gpointer init;
115
116         GModule *mod;
117
118         if (pl->mod) {
119                 dbg(0,"can't load '%s', already loaded\n", pl->name);
120                 return 0;
121         }
122         mod=g_module_open(pl->name, G_MODULE_BIND_LOCAL | (pl->lazy ? G_MODULE_BIND_LAZY : 0));
123         if (! mod) {
124                 dbg(0,"can't load '%s', Error '%s'\n", pl->name, g_module_error());
125                 return 0;
126         }
127         if (!g_module_symbol(mod, "plugin_init", &init)) {
128                 dbg(0,"can't load '%s', plugin_init not found\n", pl->name);
129                 g_module_close(mod);
130                 return 0;
131         } else {
132                 pl->mod=mod;
133                 pl->init=init;
134         }
135         return 1;
136 #else
137         return 0;
138 #endif
139 }
140
141 char *
142 plugin_get_name(struct plugin *pl)
143 {
144         return pl->name;
145 }
146
147 int
148 plugin_get_active(struct plugin *pl)
149 {
150         return pl->active;
151 }
152
153 void
154 plugin_set_active(struct plugin *pl, int active)
155 {
156         pl->active=active;
157 }
158
159 void
160 plugin_set_lazy(struct plugin *pl, int lazy)
161 {
162         pl->lazy=lazy;
163 }
164
165 #ifdef USE_PLUGINS
166 static int
167 plugin_get_ondemand(struct plugin *pl)
168 {
169         return pl->ondemand;
170 }
171 #endif
172
173 static void
174 plugin_set_ondemand(struct plugin *pl, int ondemand)
175 {
176         pl->ondemand=ondemand;
177 }
178
179 void
180 plugin_call_init(struct plugin *pl)
181 {
182         pl->init();
183 }
184
185 void
186 plugin_unload(struct plugin *pl)
187 {
188 #ifdef USE_PLUGINS
189         g_module_close(pl->mod);
190         pl->mod=NULL;
191 #endif
192 }
193
194 void
195 plugin_destroy(struct plugin *pl)
196 {
197         g_free(pl);
198 }
199
200 struct plugins *
201 plugins_new(void)
202 {
203         struct plugins *ret=g_new0(struct plugins, 1);
204         ret->hash=g_hash_table_new(g_str_hash, g_str_equal);
205         pls=ret;
206         return ret;
207 }
208
209 struct plugin *
210 plugin_new(struct attr *parent, struct attr **attrs) {
211 #ifdef USE_PLUGINS
212         struct attr *path_attr, *attr;
213         struct file_wordexp *we;
214         int active=1; // default active
215         int lazy=0, ondemand=0;
216         int i, count;
217         char **array;
218         char *name;
219         struct plugin *pl;
220         struct plugins *pls;
221
222         pls=parent->u.plugins;
223
224         if (! (path_attr=attr_search(attrs, NULL, attr_path))) {
225                 dbg(0,"missing path\n");
226                 return NULL;
227         }
228         if ( (attr=attr_search(attrs, NULL, attr_active))) {
229                 active=attr->u.num;
230         }
231         if ( (attr=attr_search(attrs, NULL, attr_lazy))) {
232                 lazy=attr->u.num;
233         }
234         if ( (attr=attr_search(attrs, NULL, attr_ondemand))) {
235                 ondemand=attr->u.num;
236         }
237         dbg(1, "path=\"%s\", active=%d, lazy=%d, ondemand=%d\n",path_attr->u.str, active, lazy, ondemand);
238
239         we=file_wordexp_new(path_attr->u.str);
240         count=file_wordexp_get_count(we);
241         array=file_wordexp_get_array(we);       
242         for (i = 0 ; i < count ; i++) {
243                 name=array[i];
244                 if (! (pl=g_hash_table_lookup(pls->hash, name))) {
245                         pl=plugin_new_from_path(name);
246                         if (! pl) {
247                                 dbg(0,"failed to create plugin '%s'\n", name);
248                                 continue;
249                         }
250                         g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
251                         pls->list=g_list_append(pls->list, pl);
252                 } else {
253                         pls->list=g_list_remove(pls->list, pl);
254                         pls->list=g_list_append(pls->list, pl);
255                 }
256                 plugin_set_active(pl, active);
257                 plugin_set_lazy(pl, lazy);
258                 plugin_set_ondemand(pl, ondemand);
259         }
260         file_wordexp_destroy(we);
261         return pl;
262 #endif
263 }
264
265 void
266 plugins_init(struct plugins *pls)
267 {
268 #ifdef USE_PLUGINS
269         struct plugin *pl;
270         GList *l;
271
272         l=pls->list;
273         while (l) {
274                 pl=l->data;
275                 if (! plugin_get_ondemand(pl)) {
276                         if (plugin_get_active(pl)) 
277                                 if (!plugin_load(pl)) 
278                                         plugin_set_active(pl, 0);
279                         if (plugin_get_active(pl)) 
280                                 plugin_call_init(pl);
281                 }
282                 l=g_list_next(l);
283         }
284 #endif
285 }
286
287 void
288 plugins_destroy(struct plugins *pls)
289 {
290         GList *l;
291         struct plugin *pl;
292
293         l=pls->list;
294         while (l) {
295                 pl=l->data;
296                 plugin_unload(pl);
297                 plugin_destroy(pl);
298         }
299         g_list_free(pls->list);
300         g_hash_table_destroy(pls->hash);
301         g_free(pls);
302 }
303
304         void *
305 plugin_get_type(enum plugin_type type, const char *type_name, const char *name)
306 {
307         dbg(1, "type=\"%s\", name=\"%s\"\n", type_name, name);
308         GList *l,*lpls;
309         struct name_val *nv;
310         struct plugin *pl;
311         char *mod_name, *filename=NULL, *corename=NULL;
312         l=plugin_types[type];
313         while (l) {
314                 nv=l->data;
315                 if (!g_ascii_strcasecmp(nv->name, name))
316                         return nv->val;
317                 l=g_list_next(l);
318         }
319         if (!pls)
320                 return NULL;
321         lpls=pls->list;
322         if(!g_ascii_strcasecmp(type_name, "map"))
323                 type_name="data";
324         filename=g_strjoin("", "lib", type_name, "_", name, NULL);
325         corename=g_strjoin("", "lib", type_name, "_", "core", NULL);
326         while (lpls) {
327                 pl=lpls->data;
328                 if ((mod_name=g_strrstr(pl->name, "/")))
329                         mod_name++;
330                 else
331                         mod_name=pl->name;
332                 if (!g_ascii_strncasecmp(mod_name, filename, strlen(filename)) || !g_ascii_strncasecmp(mod_name, corename, strlen(filename))) {
333                         dbg(1, "Loading module \"%s\"\n",pl->name) ;
334                         if (plugin_get_active(pl)) 
335                                 if (!plugin_load(pl)) 
336                                         plugin_set_active(pl, 0);
337                         if (plugin_get_active(pl)) 
338                                 plugin_call_init(pl);
339                         l=plugin_types[type];
340                         while (l) {
341                                 nv=l->data;
342                                 if (!g_ascii_strcasecmp(nv->name, name)) {
343                                         g_free(filename);
344                                         g_free(corename);
345                                         return nv->val;
346                                 }
347                                 l=g_list_next(l);
348                         }
349                 }
350                 lpls=g_list_next(lpls);
351         }
352         g_free(filename);
353         g_free(corename);
354         return NULL;
355 }