Fix:Android:Correct surface handling
[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=NULL;
220         struct plugins *pls=NULL;
221
222         if (parent)
223                 pls=parent->u.plugins;
224
225         if (! (path_attr=attr_search(attrs, NULL, attr_path))) {
226                 dbg(0,"missing path\n");
227                 return NULL;
228         }
229         if ( (attr=attr_search(attrs, NULL, attr_active))) {
230                 active=attr->u.num;
231         }
232         if ( (attr=attr_search(attrs, NULL, attr_lazy))) {
233                 lazy=attr->u.num;
234         }
235         if ( (attr=attr_search(attrs, NULL, attr_ondemand))) {
236                 ondemand=attr->u.num;
237         }
238         dbg(1, "path=\"%s\", active=%d, lazy=%d, ondemand=%d\n",path_attr->u.str, active, lazy, ondemand);
239
240         we=file_wordexp_new(path_attr->u.str);
241         count=file_wordexp_get_count(we);
242         array=file_wordexp_get_array(we);       
243         dbg(2,"expanded to %d words\n",count);
244         if (count != 1 || file_exists(array[0])) {
245                 for (i = 0 ; i < count ; i++) {
246                         name=array[i];
247                         dbg(2,"name[%d]='%s'\n", i, name);
248                         if (! (pls && (pl=g_hash_table_lookup(pls->hash, name)))) {
249                                 pl=plugin_new_from_path(name);
250                                 if (! pl) {
251                                         dbg(0,"failed to create plugin '%s'\n", name);
252                                         continue;
253                                 }
254                                 if (pls) {
255                                         g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
256                                         pls->list=g_list_append(pls->list, pl);
257                                 }
258                         } else {
259                                 if (pls) {
260                                         pls->list=g_list_remove(pls->list, pl);
261                                         pls->list=g_list_append(pls->list, pl);
262                                 }
263                         }
264                         plugin_set_active(pl, active);
265                         plugin_set_lazy(pl, lazy);
266                         plugin_set_ondemand(pl, ondemand);
267                         if (!pls && active) {
268                                 if (!plugin_load(pl)) 
269                                         plugin_set_active(pl, 0);
270                                 else
271                                         plugin_call_init(pl);
272                         }
273                 }
274                 file_wordexp_destroy(we);
275         }
276         return pl;
277 #endif
278 }
279
280 void
281 plugins_init(struct plugins *pls)
282 {
283 #ifdef USE_PLUGINS
284         struct plugin *pl;
285         GList *l;
286
287         l=pls->list;
288         while (l) {
289                 pl=l->data;
290                 if (! plugin_get_ondemand(pl)) {
291                         if (plugin_get_active(pl)) 
292                                 if (!plugin_load(pl)) 
293                                         plugin_set_active(pl, 0);
294                         if (plugin_get_active(pl)) 
295                                 plugin_call_init(pl);
296                 }
297                 l=g_list_next(l);
298         }
299 #endif
300 }
301
302 void
303 plugins_destroy(struct plugins *pls)
304 {
305         GList *l;
306         struct plugin *pl;
307
308         l=pls->list;
309         while (l) {
310                 pl=l->data;
311                 plugin_unload(pl);
312                 plugin_destroy(pl);
313         }
314         g_list_free(pls->list);
315         g_hash_table_destroy(pls->hash);
316         g_free(pls);
317 }
318
319         void *
320 plugin_get_type(enum plugin_type type, const char *type_name, const char *name)
321 {
322         dbg(1, "type=\"%s\", name=\"%s\"\n", type_name, name);
323         GList *l,*lpls;
324         struct name_val *nv;
325         struct plugin *pl;
326         char *mod_name, *filename=NULL, *corename=NULL;
327         l=plugin_types[type];
328         while (l) {
329                 nv=l->data;
330                 if (!g_ascii_strcasecmp(nv->name, name))
331                         return nv->val;
332                 l=g_list_next(l);
333         }
334         if (!pls)
335                 return NULL;
336         lpls=pls->list;
337         filename=g_strjoin("", "lib", type_name, "_", name, NULL);
338         corename=g_strjoin("", "lib", type_name, "_", "core", NULL);
339         while (lpls) {
340                 pl=lpls->data;
341                 if ((mod_name=g_strrstr(pl->name, "/")))
342                         mod_name++;
343                 else
344                         mod_name=pl->name;
345                 dbg(2,"compare '%s' with '%s'\n", mod_name, filename);
346                 if (!g_ascii_strncasecmp(mod_name, filename, strlen(filename)) || !g_ascii_strncasecmp(mod_name, corename, strlen(corename))) {
347                         dbg(1, "Loading module \"%s\"\n",pl->name) ;
348                         if (plugin_get_active(pl)) 
349                                 if (!plugin_load(pl)) 
350                                         plugin_set_active(pl, 0);
351                         if (plugin_get_active(pl)) 
352                                 plugin_call_init(pl);
353                         l=plugin_types[type];
354                         while (l) {
355                                 nv=l->data;
356                                 if (!g_ascii_strcasecmp(nv->name, name)) {
357                                         g_free(filename);
358                                         g_free(corename);
359                                         return nv->val;
360                                 }
361                                 l=g_list_next(l);
362                         }
363                 }
364                 lpls=g_list_next(lpls);
365         }
366         g_free(filename);
367         g_free(corename);
368         return NULL;
369 }