/* -*- C++ -*- * Copyright ©2005 Hugo Mills * * This software is distributed under the terms of the GNU GPL v3 * For more information on the GPL, see the file COPYING or * visit http://www.gnu.org/ * * This software is distributed without warranty */ #include "plugins.h" #include #include #include #include #include "contentgroup.h" #include "magellan/options.h" #include std::list map_plugins; std::list orbit_plugins; std::list content_plugins; std::list output_plugins; std::list viewport_plugins; std::list display_plugins; typedef PluginInfo* (*InitFunction)(int); template bool try_insert(std::list& container, PluginInfo* p) { T* cast = dynamic_cast(p); if(cast != NULL) { for(typename std::list::const_iterator it = container.begin(); it != container.end(); it++) { if((*it)->name == cast->name) { if(opts->debug_plugin() >= 1) { std::cerr << "Plugin from " << cast->file << " has same name (" << cast->name << ") as previously-loaded plugin from " << (*it)->file << ". Skipping." << std::endl; } return true; // Falsely claim that everything is OK. } } // If we've got here, we've not seen the plugin before, so // load it container.push_back(cast); } return cast != NULL; } void load_plugins(void) { for(Options::psearch_it it = opts->plugin_dir_start(); it != opts->plugin_dir_end(); it++) { DIR* dir = opendir(it->c_str()); if(dir == NULL) { if(opts->debug_plugin() >= 1) { std::cerr << "Plugin loader: can't open " << *it << ": " << strerror(errno) << std::endl; } continue; } if(opts->debug_plugin() >= 1) std::cerr << "Opening plugin dir " << *it << std::endl; struct dirent* file; // For each entry in the directory while(file = readdir(dir)) { // Check that it's a .so if(opts->debug_plugin() >= 2) std::cerr << "Checking file " << file->d_name << std::endl; if(strncmp(file->d_name + strlen(file->d_name)-3, ".so", 3) != 0) continue; // Open the library std::string fname = *it; fname += file->d_name; void* lib = dlopen(fname.c_str(), RTLD_LAZY | RTLD_GLOBAL); if(opts->debug_plugin() >= 2) std::cerr << " (opened)" << std::endl; if(lib != NULL) { void *symbol; PluginInfo* (*init)(int); symbol = dlsym(lib, "getmodules"); if(symbol == NULL) { std::cerr << "Plugin " << fname << " doesn't have getmodules() function" << std::endl; continue; } init = (InitFunction)(symbol); PluginInfo* res; int i=0; while(res = init(i++)) { res->file = fname; if(try_insert(map_plugins, res) || try_insert(orbit_plugins, res) || try_insert(content_plugins, res) || try_insert(output_plugins, res) || try_insert(viewport_plugins, res) ) { } else { std::cerr << "Plugin " << fname << " not a recognised plugin type?" << std::endl; continue; } if(opts->debug_plugin() >= 1) { std::cout << "Loaded: " << res->name << " v"; std::cout << (res->version>>16 & 0xff) << "."; std::cout << (res->version>>8 & 0xff) << "."; std::cout << (res->version & 0xff); std::cout << " (" << file->d_name << ")" << std::endl; } } } else { if(opts->debug_plugin() >= 2) std::cerr << " Error dlopen()ing the file" << std::endl; std::cout << dlerror() << std::endl; } } closedir(dir); } PluginInfo_Content* contentgroup = dynamic_cast(ContentGroup::getmodules(0)); ContentGroup::set_content_plugins(&content_plugins); content_plugins.push_back(contentgroup); PluginInfo_Viewport* vp = dynamic_cast(XfView::getmodules(0)); viewport_plugins.push_back(vp); PluginInfo_Display* di = dynamic_cast(MDisplay::getmodules(0)); display_plugins.push_back(di); } template void unload_plugins(Iterator start, Iterator end) { for(Iterator it = start; it != end; ++it) { /* FIXME: Uninitialised pointer use here if((*it)->library != NULL) { dlclose((*it)->library); } */ delete (*it); } } void unload_plugins(void) { unload_plugins(map_plugins.begin(), map_plugins.end()); unload_plugins(orbit_plugins.begin(), orbit_plugins.end()); unload_plugins(content_plugins.begin(), content_plugins.end()); unload_plugins(output_plugins.begin(), output_plugins.end()); unload_plugins(viewport_plugins.begin(), viewport_plugins.end()); unload_plugins(display_plugins.begin(), display_plugins.end()); map_plugins.clear(); orbit_plugins.clear(); content_plugins.clear(); output_plugins.clear(); viewport_plugins.clear(); display_plugins.clear(); }