FIX:core:fix the fix do not crash if plugins are not in config
[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 #include <gmodule.h>
25 #endif
26 #include "plugin.h"
27 #include "file.h"
28 #define PLUGIN_C
29 #include "plugin.h"
30 #include "item.h"
31 #include "debug.h"
32
33 struct plugin {
34         int active;
35         int lazy;
36         int ondemand;
37         char *name;
38 #ifdef USE_PLUGINS
39         GModule *mod;
40 #endif
41         void (*init)(void);
42 };
43
44 struct plugins {
45         GHashTable *hash;
46         GList *list;
47 } *pls;
48
49 struct plugin *
50 plugin_new(char *plugin)
51 {
52 #ifdef USE_PLUGINS
53         struct plugin *ret;
54         if (! g_module_supported()) {
55                 return NULL;
56         }
57         ret=g_new0(struct plugin, 1);
58         ret->name=g_strdup(plugin);
59         return ret;
60 #else
61         return NULL;
62 #endif
63 }
64
65 int
66 plugin_load(struct plugin *pl)
67 {
68 #ifdef USE_PLUGINS
69         gpointer init;
70
71         GModule *mod;
72
73         if (pl->mod) {
74                 dbg(0,"can't load '%s', already loaded\n", pl->name);
75                 return 0;
76         }
77         mod=g_module_open(pl->name, G_MODULE_BIND_LOCAL | (pl->lazy ? G_MODULE_BIND_LAZY : 0));
78         if (! mod) {
79                 dbg(0,"can't load '%s', Error '%s'\n", pl->name, g_module_error());
80                 return 0;
81         }
82         if (!g_module_symbol(mod, "plugin_init", &init)) {
83                 dbg(0,"can't load '%s', plugin_init not found\n", pl->name);
84                 g_module_close(mod);
85                 return 0;
86         } else {
87                 pl->mod=mod;
88                 pl->init=init;
89         }
90         return 1;
91 #else
92         return 0;
93 #endif
94 }
95
96 char *
97 plugin_get_name(struct plugin *pl)
98 {
99         return pl->name;
100 }
101
102 int
103 plugin_get_active(struct plugin *pl)
104 {
105         return pl->active;
106 }
107
108 void
109 plugin_set_active(struct plugin *pl, int active)
110 {
111         pl->active=active;
112 }
113
114 void
115 plugin_set_lazy(struct plugin *pl, int lazy)
116 {
117         pl->lazy=lazy;
118 }
119
120 #ifdef USE_PLUGINS
121 static int
122 plugin_get_ondemand(struct plugin *pl)
123 {
124         return pl->ondemand;
125 }
126 #endif
127
128 static void
129 plugin_set_ondemand(struct plugin *pl, int ondemand)
130 {
131         pl->ondemand=ondemand;
132 }
133
134 void
135 plugin_call_init(struct plugin *pl)
136 {
137         pl->init();
138 }
139
140 void
141 plugin_unload(struct plugin *pl)
142 {
143 #ifdef USE_PLUGINS
144         g_module_close(pl->mod);
145         pl->mod=NULL;
146 #endif
147 }
148
149 void
150 plugin_destroy(struct plugin *pl)
151 {
152         g_free(pl);
153 }
154
155 struct plugins *
156 plugins_new(void)
157 {
158         struct plugins *ret=g_new0(struct plugins, 1);
159         ret->hash=g_hash_table_new(g_str_hash, g_str_equal);
160         pls=ret;
161         return ret;
162 }
163
164 void
165 plugins_add_path(struct plugins *pls, struct attr **attrs) {
166 #ifdef USE_PLUGINS 
167         struct attr *path_attr, *attr;
168         struct file_wordexp *we;
169         int active=1; // default active
170         int lazy=0, ondemand=0;
171         int i, count;
172         char **array;
173         char *name;
174         struct plugin *pl;
175
176         if (! (path_attr=attr_search(attrs, NULL, attr_path))) {
177                 dbg(0,"missing path\n");
178                 return;
179         }
180         if ( (attr=attr_search(attrs, NULL, attr_active))) {
181                 active=attr->u.num;
182         }
183         if ( (attr=attr_search(attrs, NULL, attr_lazy))) {
184                 lazy=attr->u.num;
185         }
186         if ( (attr=attr_search(attrs, NULL, attr_ondemand))) {
187                 ondemand=attr->u.num;
188         }
189         dbg(1, "path=\"%s\", active=%d, lazy=%d, ondemand=%d\n",path_attr->u.str, active, lazy, ondemand);
190
191         we=file_wordexp_new(path_attr->u.str);
192         count=file_wordexp_get_count(we);
193         array=file_wordexp_get_array(we);       
194         for (i = 0 ; i < count ; i++) {
195                 name=array[i];
196                 if (! (pl=g_hash_table_lookup(pls->hash, name))) {
197                         pl=plugin_new(name);
198                         if (! pl) {
199                                 dbg(0,"failed to create plugin '%s'\n", name);
200                                 continue;
201                         }
202                         g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
203                         pls->list=g_list_append(pls->list, pl);
204                 } else {
205                         pls->list=g_list_remove(pls->list, pl);
206                         pls->list=g_list_append(pls->list, pl);
207                 }
208                 plugin_set_active(pl, active);
209                 plugin_set_lazy(pl, lazy);
210                 plugin_set_ondemand(pl, ondemand);
211         }
212         file_wordexp_destroy(we);
213 #endif
214 }
215
216 void
217 plugins_init(struct plugins *pls)
218 {
219 #ifdef USE_PLUGINS
220         struct plugin *pl;
221         GList *l;
222
223         l=pls->list;
224         while (l) {
225                 pl=l->data;
226                 if (! plugin_get_ondemand(pl)) {
227                         if (plugin_get_active(pl)) 
228                                 if (!plugin_load(pl)) 
229                                         plugin_set_active(pl, 0);
230                         if (plugin_get_active(pl)) 
231                                 plugin_call_init(pl);
232                 }
233                 l=g_list_next(l);
234         }
235 #endif
236 }
237
238 void
239 plugins_destroy(struct plugins *pls)
240 {
241         GList *l;
242         struct plugin *pl;
243
244         l=pls->list;
245         while (l) {
246                 pl=l->data;
247                 plugin_unload(pl);
248                 plugin_destroy(pl);
249         }
250         g_list_free(pls->list);
251         g_hash_table_destroy(pls->hash);
252         g_free(pls);
253 }
254
255         void *
256 plugin_get_type(enum plugin_type type, const char *type_name, const char *name)
257 {
258         dbg(1, "type=\"%s\", name=\"%s\"\n", type_name, name);
259         GList *l,*lpls;
260         struct name_val *nv;
261         struct plugin *pl;
262         char *mod_name, *filename=NULL, *corename=NULL;
263         l=plugin_types[type];
264         while (l) {
265                 nv=l->data;
266                 if (!g_ascii_strcasecmp(nv->name, name))
267                         return nv->val;
268                 l=g_list_next(l);
269         }
270         if (!pls)
271                 return NULL;
272         lpls=pls->list;
273         if(!g_ascii_strcasecmp(type_name, "map"))
274                 type_name="data";
275         filename=g_strjoin("", "lib", type_name, "_", name, NULL);
276         corename=g_strjoin("", "lib", type_name, "_", "core", NULL);
277         while (lpls) {
278                 pl=lpls->data;
279                 if ((mod_name=g_strrstr(pl->name, "/")))
280                         mod_name++;
281                 else
282                         mod_name=pl->name;
283                 if (!g_ascii_strncasecmp(mod_name, filename, strlen(filename)) || !g_ascii_strncasecmp(mod_name, corename, strlen(filename))) {
284                         dbg(0, "Loading module \"%s\"\n",pl->name) ;
285                         if (plugin_get_active(pl)) 
286                                 if (!plugin_load(pl)) 
287                                         plugin_set_active(pl, 0);
288                         if (plugin_get_active(pl)) 
289                                 plugin_call_init(pl);
290                         l=plugin_types[type];
291                         while (l) {
292                                 nv=l->data;
293                                 if (!g_ascii_strcasecmp(nv->name, name)) {
294                                         g_free(filename);
295                                         g_free(corename);
296                                         return nv->val;
297                                 }
298                                 l=g_list_next(l);
299                         }
300                 }
301                 lpls=g_list_next(lpls);
302         }
303         g_free(filename);
304         g_free(corename);
305         return NULL;
306 }