Fix:maptool:Another name for faroe islands
[navit-package] / navit / plugin.c
index 7f52301..991eb50 100644 (file)
+/**
+ * Navit, a modular navigation system.
+ * Copyright (C) 2005-2008 Navit Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <string.h>
 #include <glib.h>
-#include <gmodule.h>
 #include "config.h"
+#ifdef USE_PLUGINS
+#ifdef HAVE_GMODULE
+#include <gmodule.h>
+#else
+#include <dlfcn.h>
+#endif
+#endif
 #include "plugin.h"
 #include "file.h"
 #define PLUGIN_C
 #include "plugin.h"
+#include "item.h"
+#include "debug.h"
+
+#ifdef USE_PLUGINS
+#ifndef HAVE_GMODULE
+typedef void * GModule;
+#define G_MODULE_BIND_LOCAL 1
+#define G_MODULE_BIND_LAZY 2
+static int
+g_module_supported(void)
+{
+       return 1;
+}
+
+static void *
+g_module_open(char *name, int flags)
+{
+       return dlopen(name,
+               (flags & G_MODULE_BIND_LAZY ? RTLD_LAZY : RTLD_NOW) |
+               (flags & G_MODULE_BIND_LOCAL ? RTLD_LOCAL : RTLD_GLOBAL));
+}
+
+static char *
+g_module_error(void)
+{
+       return dlerror();
+}
+
+static int
+g_module_symbol(GModule *handle, char *symbol, gpointer *addr)
+{
+       *addr=dlsym(handle, symbol);
+       return (*addr != NULL);
+}
+
+static void
+g_module_close(GModule *handle)
+{
+       dlclose(handle);
+}
+
+#endif
+#endif
 
 struct plugin {
        int active;
        int lazy;
+       int ondemand;
        char *name;
+#ifdef USE_PLUGINS
        GModule *mod;
+#endif
        void (*init)(void);
 };
 
 struct plugins {
        GHashTable *hash;
        GList *list;
-};
+} *pls;
 
-struct plugin *
-plugin_new(char *plugin)
+static struct plugin *
+plugin_new_from_path(char *plugin)
 {
+#ifdef USE_PLUGINS
        struct plugin *ret;
        if (! g_module_supported()) {
-               return NULL;
+              return NULL;
        }
        ret=g_new0(struct plugin, 1);
        ret->name=g_strdup(plugin);
        return ret;
-       
+#else
+       return NULL;
+#endif
 }
 
 int
 plugin_load(struct plugin *pl)
 {
+#ifdef USE_PLUGINS
        gpointer init;
 
        GModule *mod;
 
        if (pl->mod) {
-               g_warning("can't load '%s', already loaded\n", pl->name);
+               dbg(0,"can't load '%s', already loaded\n", pl->name);
                return 0;
        }
        mod=g_module_open(pl->name, G_MODULE_BIND_LOCAL | (pl->lazy ? G_MODULE_BIND_LAZY : 0));
        if (! mod) {
-               g_warning("can't load '%s', Error '%s'\n", pl->name, g_module_error());
+               dbg(0,"can't load '%s', Error '%s'\n", pl->name, g_module_error());
                return 0;
        }
        if (!g_module_symbol(mod, "plugin_init", &init)) {
-               g_warning("can't load '%s', plugin_init not found\n", pl->name);
+               dbg(0,"can't load '%s', plugin_init not found\n", pl->name);
                g_module_close(mod);
                return 0;
        } else {
@@ -57,6 +133,9 @@ plugin_load(struct plugin *pl)
                pl->init=init;
        }
        return 1;
+#else
+       return 0;
+#endif
 }
 
 char *
@@ -83,6 +162,20 @@ plugin_set_lazy(struct plugin *pl, int lazy)
        pl->lazy=lazy;
 }
 
+#ifdef USE_PLUGINS
+static int
+plugin_get_ondemand(struct plugin *pl)
+{
+       return pl->ondemand;
+}
+#endif
+
+static void
+plugin_set_ondemand(struct plugin *pl, int ondemand)
+{
+       pl->ondemand=ondemand;
+}
+
 void
 plugin_call_init(struct plugin *pl)
 {
@@ -92,8 +185,10 @@ plugin_call_init(struct plugin *pl)
 void
 plugin_unload(struct plugin *pl)
 {
+#ifdef USE_PLUGINS
        g_module_close(pl->mod);
        pl->mod=NULL;
+#endif
 }
 
 void
@@ -107,39 +202,79 @@ plugins_new(void)
 {
        struct plugins *ret=g_new0(struct plugins, 1);
        ret->hash=g_hash_table_new(g_str_hash, g_str_equal);
+       pls=ret;
        return ret;
 }
 
-void
-plugins_add_path(struct plugins *pls, const char *path, int active, int lazy)
-{
+struct plugin *
+plugin_new(struct attr *parent, struct attr **attrs) {
+#ifdef USE_PLUGINS
+       struct attr *path_attr, *attr;
        struct file_wordexp *we;
+       int active=1; // default active
+       int lazy=0, ondemand=0;
        int i, count;
        char **array;
        char *name;
-       struct plugin *pl;
+       struct plugin *pl=NULL;
+       struct plugins *pls=NULL;
+
+       if (parent)
+               pls=parent->u.plugins;
+
+       if (! (path_attr=attr_search(attrs, NULL, attr_path))) {
+               dbg(0,"missing path\n");
+               return NULL;
+       }
+       if ( (attr=attr_search(attrs, NULL, attr_active))) {
+               active=attr->u.num;
+       }
+       if ( (attr=attr_search(attrs, NULL, attr_lazy))) {
+               lazy=attr->u.num;
+       }
+       if ( (attr=attr_search(attrs, NULL, attr_ondemand))) {
+               ondemand=attr->u.num;
+       }
+       dbg(1, "path=\"%s\", active=%d, lazy=%d, ondemand=%d\n",path_attr->u.str, active, lazy, ondemand);
 
-       we=file_wordexp_new(path);
+       we=file_wordexp_new(path_attr->u.str);
        count=file_wordexp_get_count(we);
        array=file_wordexp_get_array(we);       
-       for (i = 0 ; i < count ; i++) {
-               name=array[i];
-               if (! (pl=g_hash_table_lookup(pls->hash, name))) {
-                       pl=plugin_new(name);
-                       if (! pl) {
-                               g_warning("failed to create plugin '%s'\n", name);
-                               continue;
+       dbg(2,"expanded to %d words\n",count);
+       if (count != 1 || file_exists(array[0])) {
+               for (i = 0 ; i < count ; i++) {
+                       name=array[i];
+                       dbg(2,"name[%d]='%s'\n", i, name);
+                       if (! (pls && (pl=g_hash_table_lookup(pls->hash, name)))) {
+                               pl=plugin_new_from_path(name);
+                               if (! pl) {
+                                       dbg(0,"failed to create plugin '%s'\n", name);
+                                       continue;
+                               }
+                               if (pls) {
+                                       g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
+                                       pls->list=g_list_append(pls->list, pl);
+                               }
+                       } else {
+                               if (pls) {
+                                       pls->list=g_list_remove(pls->list, pl);
+                                       pls->list=g_list_append(pls->list, pl);
+                               }
+                       }
+                       plugin_set_active(pl, active);
+                       plugin_set_lazy(pl, lazy);
+                       plugin_set_ondemand(pl, ondemand);
+                       if (!pls && active) {
+                               if (!plugin_load(pl)) 
+                                       plugin_set_active(pl, 0);
+                               else
+                                       plugin_call_init(pl);
                        }
-                       g_hash_table_insert(pls->hash, plugin_get_name(pl), pl);
-                       pls->list=g_list_append(pls->list, pl);
-               } else {
-                       pls->list=g_list_remove(pls->list, pl);
-                       pls->list=g_list_append(pls->list, pl);
                }
-               plugin_set_active(pl, active);
-               plugin_set_lazy(pl, lazy);
+               file_wordexp_destroy(we);
        }
-       file_wordexp_destroy(we);
+       return pl;
+#endif
 }
 
 void
@@ -152,16 +287,13 @@ plugins_init(struct plugins *pls)
        l=pls->list;
        while (l) {
                pl=l->data;
-               if (plugin_get_active(pl)) 
-                       if (!plugin_load(pl)) 
-                               plugin_set_active(pl, 0);
-               l=g_list_next(l);
-       }
-       l=pls->list;
-       while (l) {
-               pl=l->data;
-               if (plugin_get_active(pl)) 
-                       plugin_call_init(pl);
+               if (! plugin_get_ondemand(pl)) {
+                       if (plugin_get_active(pl)) 
+                               if (!plugin_load(pl)) 
+                                       plugin_set_active(pl, 0);
+                       if (plugin_get_active(pl)) 
+                               plugin_call_init(pl);
+               }
                l=g_list_next(l);
        }
 #endif
@@ -184,17 +316,54 @@ plugins_destroy(struct plugins *pls)
        g_free(pls);
 }
 
-void *
-plugin_get_type(enum plugin_type type, const char *name)
+       void *
+plugin_get_type(enum plugin_type type, const char *type_name, const char *name)
 {
-       GList *l;
+       dbg(1, "type=\"%s\", name=\"%s\"\n", type_name, name);
+       GList *l,*lpls;
        struct name_val *nv;
+       struct plugin *pl;
+       char *mod_name, *filename=NULL, *corename=NULL;
        l=plugin_types[type];
        while (l) {
                nv=l->data;
-               if (!g_ascii_strcasecmp(nv->name, name))
+               if (!g_ascii_strcasecmp(nv->name, name))
                        return nv->val;
                l=g_list_next(l);
        }
+       if (!pls)
+               return NULL;
+       lpls=pls->list;
+       filename=g_strjoin("", "lib", type_name, "_", name, NULL);
+       corename=g_strjoin("", "lib", type_name, "_", "core", NULL);
+       while (lpls) {
+               pl=lpls->data;
+               if ((mod_name=g_strrstr(pl->name, "/")))
+                       mod_name++;
+               else
+                       mod_name=pl->name;
+               dbg(2,"compare '%s' with '%s'\n", mod_name, filename);
+               if (!g_ascii_strncasecmp(mod_name, filename, strlen(filename)) || !g_ascii_strncasecmp(mod_name, corename, strlen(corename))) {
+                       dbg(1, "Loading module \"%s\"\n",pl->name) ;
+                       if (plugin_get_active(pl)) 
+                               if (!plugin_load(pl)) 
+                                       plugin_set_active(pl, 0);
+                       if (plugin_get_active(pl)) 
+                               plugin_call_init(pl);
+                       l=plugin_types[type];
+                       while (l) {
+                               nv=l->data;
+                               if (!g_ascii_strcasecmp(nv->name, name)) {
+                                       g_free(filename);
+                                       g_free(corename);
+                                       return nv->val;
+                               }
+                               l=g_list_next(l);
+                       }
+               }
+               lpls=g_list_next(lpls);
+       }
+       g_free(filename);
+       g_free(corename);
        return NULL;
 }