Fix:map_csv:Disable default notification of each deleted item.
[profile/ivi/navit.git] / navit / 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 #ifdef HAVE_API_WIN32_BASE
28 #include <windows.h>
29 #else
30 #include <dlfcn.h>
31 #endif
32 #endif
33 #endif
34 #include "plugin.h"
35 #include "file.h"
36 #define PLUGIN_C
37 #include "plugin.h"
38 #include "item.h"
39 #include "debug.h"
40
41 #ifdef USE_PLUGINS
42 #ifndef HAVE_GMODULE
43 typedef void * GModule;
44 #define G_MODULE_BIND_LOCAL 1
45 #define G_MODULE_BIND_LAZY 2
46 static int
47 g_module_supported(void)
48 {
49         return 1;
50 }
51
52 #ifdef HAVE_API_WIN32_BASE
53
54 static DWORD last_error;
55 static char errormsg[64];
56
57 static void *
58 g_module_open(char *name, int flags)
59 {
60         HINSTANCE handle;
61         int len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, 0, 0);
62         wchar_t filename[len];
63         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, filename, len) ;
64
65         handle = LoadLibraryW (filename);
66         if (!handle)
67                 last_error=GetLastError();
68         return handle;
69 }
70
71 static char *
72 g_module_error(void)
73 {
74         sprintf(errormsg,"dll error %d",(int)last_error);
75         return errormsg;
76 }
77
78 static int
79 g_module_symbol(GModule *handle, char *symbol, gpointer *addr)
80 {
81 #ifdef HAVE_API_WIN32_CE
82         int len=MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, symbol, -1, 0, 0);
83         wchar_t wsymbol[len+1];
84         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, symbol, -1, wsymbol, len) ;
85         *addr=GetProcAddress ((HANDLE)handle, wsymbol);
86 #else
87         *addr=GetProcAddress ((HANDLE)handle, symbol);
88 #endif
89         if (*addr)
90                 return 1;
91         last_error=GetLastError();
92         return 0;
93 }
94
95 static void
96 g_module_close(GModule *handle)
97 {
98         FreeLibrary((HANDLE)handle);
99 }
100
101 #else
102 static void *
103 g_module_open(char *name, int flags)
104 {
105         return dlopen(name,
106                 (flags & G_MODULE_BIND_LAZY ? RTLD_LAZY : RTLD_NOW) |
107                 (flags & G_MODULE_BIND_LOCAL ? RTLD_LOCAL : RTLD_GLOBAL));
108 }
109
110 static char *
111 g_module_error(void)
112 {
113         return dlerror();
114 }
115
116 static int
117 g_module_symbol(GModule *handle, char *symbol, gpointer *addr)
118 {
119         *addr=dlsym(handle, symbol);
120         return (*addr != NULL);
121 }
122
123 static void
124 g_module_close(GModule *handle)
125 {
126         dlclose(handle);
127 }
128 #endif
129 #endif
130 #endif
131
132 struct plugin {
133         int active;
134         int lazy;
135         int ondemand;
136         char *name;
137 #ifdef USE_PLUGINS
138         GModule *mod;
139 #endif
140         void (*init)(void);
141 };
142
143 struct plugins {
144         GHashTable *hash;
145         GList *list;
146 } *pls;
147
148 static struct plugin *
149 plugin_new_from_path(char *plugin)
150 {
151 #ifdef USE_PLUGINS
152         struct plugin *ret;
153         if (! g_module_supported()) {
154                return NULL;
155         }
156         ret=g_new0(struct plugin, 1);
157         ret->name=g_strdup(plugin);
158         return ret;
159 #else
160         return NULL;
161 #endif
162 }
163
164 int
165 plugin_load(struct plugin *pl)
166 {
167 #ifdef USE_PLUGINS
168         gpointer init;
169
170         GModule *mod;
171
172         if (pl->mod) {
173                 dbg(0,"can't load '%s', already loaded\n", pl->name);
174                 return 0;
175         }
176         mod=g_module_open(pl->name, G_MODULE_BIND_LOCAL | (pl->lazy ? G_MODULE_BIND_LAZY : 0));
177         if (! mod) {
178                 dbg(0,"can't load '%s', Error '%s'\n", pl->name, g_module_error());
179                 return 0;
180         }
181         if (!g_module_symbol(mod, "plugin_init", &init)) {
182                 dbg(0,"can't load '%s', plugin_init not found\n", pl->name);
183                 g_module_close(mod);
184                 return 0;
185         } else {
186                 dbg(1, "loaded module %s\n", pl->name);
187                 pl->mod=mod;
188                 pl->init=init;
189         }
190         return 1;
191 #else
192         return 0;
193 #endif
194 }
195
196 char *
197 plugin_get_name(struct plugin *pl)
198 {
199         return pl->name;
200 }
201
202 int
203 plugin_get_active(struct plugin *pl)
204 {
205         return pl->active;
206 }
207
208 void
209 plugin_set_active(struct plugin *pl, int active)
210 {
211         pl->active=active;
212 }
213
214 void
215 plugin_set_lazy(struct plugin *pl, int lazy)
216 {
217         pl->lazy=lazy;
218 }
219
220 #ifdef USE_PLUGINS
221 static int
222 plugin_get_ondemand(struct plugin *pl)
223 {
224         return pl->ondemand;
225 }
226 #endif
227
228 static void
229 plugin_set_ondemand(struct plugin *pl, int ondemand)
230 {
231         pl->ondemand=ondemand;
232 }
233
234 void
235 plugin_call_init(struct plugin *pl)
236 {
237         pl->init();
238 }
239
240 void
241 plugin_unload(struct plugin *pl)
242 {
243 #ifdef USE_PLUGINS
244         g_module_close(pl->mod);
245         pl->mod=NULL;
246 #endif
247 }
248
249 void
250 plugin_destroy(struct plugin *pl)
251 {
252         g_free(pl);
253 }
254
255 struct plugins *
256 plugins_new(void)
257 {
258         struct plugins *ret=g_new0(struct plugins, 1);
259         ret->hash=g_hash_table_new(g_str_hash, g_str_equal);
260         pls=ret;
261         return ret;
262 }
263
264 struct plugin *
265 plugin_new(struct attr *parent, struct attr **attrs) {
266 #ifdef USE_PLUGINS
267         struct attr *path_attr, *attr;
268         struct file_wordexp *we;
269         int active=1; // default active
270         int lazy=0, ondemand=0;
271         int i, count;
272         char **array;
273         char *name;
274         struct plugin *pl=NULL;
275         struct plugins *pls=NULL;
276
277         if (parent)
278                 pls=parent->u.plugins;
279
280         if (! (path_attr=attr_search(attrs, NULL, attr_path))) {
281                 dbg(0,"missing path\n");
282                 return NULL;
283         }
284         if ( (attr=attr_search(attrs, NULL, attr_active))) {
285                 active=attr->u.num;
286         }
287         if ( (attr=attr_search(attrs, NULL, attr_lazy))) {
288                 lazy=attr->u.num;
289         }
290         if ( (attr=attr_search(attrs, NULL, attr_ondemand))) {
291                 ondemand=attr->u.num;
292         }
293         dbg(1, "path=\"%s\", active=%d, lazy=%d, ondemand=%d\n",path_attr->u.str, active, lazy, ondemand);
294
295         we=file_wordexp_new(path_attr->u.str);
296         count=file_wordexp_get_count(we);
297         array=file_wordexp_get_array(we);       
298         dbg(2,"expanded to %d words\n",count);
299         if (count != 1 || file_exists(array[0])) {
300                 for (i = 0 ; i < count ; i++) {
301                         name=array[i];
302                         dbg(2,"found plugin module file [%d]: '%s'\n", i, name);
303                         if (! (pls && (pl=g_hash_table_lookup(pls->hash, name)))) {
304                                 pl=plugin_new_from_path(name);
305                                 if (! pl) {
306                                         dbg(0,"failed to create plugin from file '%s'\n", name);
307                                         continue;
308                                 }
309                                 if (pls) {
310                                         g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
311                                         pls->list=g_list_append(pls->list, pl);
312                                 }
313                         } else {
314                                 if (pls) {
315                                         pls->list=g_list_remove(pls->list, pl);
316                                         pls->list=g_list_append(pls->list, pl);
317                                 }
318                         }
319                         plugin_set_active(pl, active);
320                         plugin_set_lazy(pl, lazy);
321                         plugin_set_ondemand(pl, ondemand);
322                         if (!pls && active) {
323                                 if (!plugin_load(pl)) 
324                                         plugin_set_active(pl, 0);
325                                 else
326                                         plugin_call_init(pl);
327                         }
328                 }
329         }
330         file_wordexp_destroy(we);
331         return pl;
332 #else
333     return 0;
334 #endif
335 }
336
337 void
338 plugins_init(struct plugins *pls)
339 {
340 #ifdef USE_PLUGINS
341         struct plugin *pl;
342         GList *l;
343
344         l=pls->list;
345         if (l){
346                 while (l) {
347                         pl=l->data;
348                         if (! plugin_get_ondemand(pl)) {
349                                 if (plugin_get_active(pl))
350                                         if (!plugin_load(pl))
351                                                 plugin_set_active(pl, 0);
352                                 if (plugin_get_active(pl))
353                                         plugin_call_init(pl);
354                         }
355                         l=g_list_next(l);
356                 }
357         } else {
358                 dbg(0, "Warning: No plugins found. Is Navit installed correctly?\n");
359         }
360 #endif
361 }
362
363 void
364 plugins_destroy(struct plugins *pls)
365 {
366         GList *l;
367         struct plugin *pl;
368
369         l=pls->list;
370         while (l) {
371                 pl=l->data;
372                 plugin_unload(pl);
373                 plugin_destroy(pl);
374         }
375         g_list_free(pls->list);
376         g_hash_table_destroy(pls->hash);
377         g_free(pls);
378 }
379
380         void *
381 plugin_get_type(enum plugin_type type, const char *type_name, const char *name)
382 {
383         GList *l,*lpls;
384         struct name_val *nv;
385         struct plugin *pl;
386         char *mod_name, *filename=NULL, *corename=NULL;
387
388         dbg(1, "type=\"%s\", name=\"%s\"\n", type_name, name);
389
390         l=plugin_types[type];
391         while (l) {
392                 nv=l->data;
393                 if (!g_ascii_strcasecmp(nv->name, name))
394                         return nv->val;
395                 l=g_list_next(l);
396         }
397         if (!pls)
398                 return NULL;
399         lpls=pls->list;
400         filename=g_strjoin("", "lib", type_name, "_", name, NULL);
401         corename=g_strjoin("", "lib", type_name, "_", "core", NULL);
402         while (lpls) {
403                 pl=lpls->data;
404                 if ((mod_name=g_strrstr(pl->name, "/")))
405                         mod_name++;
406                 else
407                         mod_name=pl->name;
408                 dbg(2,"compare '%s' with '%s'\n", mod_name, filename);
409                 if (!g_ascii_strncasecmp(mod_name, filename, strlen(filename)) || !g_ascii_strncasecmp(mod_name, corename, strlen(corename))) {
410                         dbg(1, "Loading module \"%s\"\n",pl->name) ;
411                         if (plugin_get_active(pl)) 
412                                 if (!plugin_load(pl)) 
413                                         plugin_set_active(pl, 0);
414                         if (plugin_get_active(pl)) 
415                                 plugin_call_init(pl);
416                         l=plugin_types[type];
417                         while (l) {
418                                 nv=l->data;
419                                 if (!g_ascii_strcasecmp(nv->name, name)) {
420                                         g_free(filename);
421                                         g_free(corename);
422                                         return nv->val;
423                                 }
424                                 l=g_list_next(l);
425                         }
426                 }
427                 lpls=g_list_next(lpls);
428         }
429         g_free(filename);
430         g_free(corename);
431         return NULL;
432 }