summaryrefslogtreecommitdiff
path: root/libmodman/module_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libmodman/module_manager.cpp')
-rw-r--r--libmodman/module_manager.cpp330
1 files changed, 0 insertions, 330 deletions
diff --git a/libmodman/module_manager.cpp b/libmodman/module_manager.cpp
deleted file mode 100644
index 88e6198..0000000
--- a/libmodman/module_manager.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-/*******************************************************************************
- * libmodman - A library for extending applications
- * Copyright (C) 2009 Nathaniel McCallum <nathaniel@natemccallum.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ******************************************************************************/
-
-#include <algorithm> // For sort()
-#include <sys/stat.h> // For stat()
-#include <iostream>
-#include <typeinfo>
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <dlfcn.h> // For dlopen(), etc...
-#include <dirent.h> // For opendir(), readdir(), closedir()
-#endif
-
-#include "module_manager.hpp"
-using namespace libmodman;
-
-#include <cstdio>
-
-#define _LOAD_FAIL -1
-#define _LOAD_LAZY 0
-#define _LOAD_SUCC 1
-
-#ifdef WIN32
-#define pdlmtype HMODULE
-#define pdlopenl(filename) LoadLibraryEx(filename, NULL, DONT_RESOLVE_DLL_REFERENCES)
-#define pdlclose(module) FreeLibrary((pdlmtype) module)
-static void* pdlsym(pdlmtype mod, const string &sym) {
- return (void *) GetProcAddress(mod, sym.c_str());
-}
-
-static pdlmtype pdlreopen(const char* filename, pdlmtype module) {
- pdlclose(module);
- return LoadLibrary(filename);
-}
-
-static string pdlerror() {
- std::string e;
- LPTSTR msg;
-
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER |FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &msg,
- 0,
- NULL);
- e = std::string((const char*) msg);
- LocalFree(msg);
- return e;
-}
-
-static bool pdlsymlinked(const char* modn, const char* symb) {
- return (GetProcAddress(GetModuleHandle(modn), symb) != NULL || \
- GetProcAddress(GetModuleHandle(NULL), symb) != NULL);
-}
-
-static string prep_type_name(string name) {
- string prefix = "<class ";
- string suffix = ",";
- if (name.find(prefix) != name.npos)
- name = name.substr(name.find(prefix) + prefix.size());
- if (name.find(suffix) != name.npos)
- name = name.substr(0, name.find(suffix));
- return name;
-}
-#else
-#define pdlmtype void*
-#define pdlopenl(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL)
-#define pdlclose(module) dlclose((pdlmtype) module)
-#define pdlreopen(filename, module) module
-static void* pdlsym(pdlmtype mod, const string &sym) {
- return dlsym(mod, sym.c_str());
-}
-
-static string pdlerror() {
- return dlerror();
-}
-
-bool pdlsymlinked(const char* modn, const char* symb) {
- void* mod = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL);
- if (mod) {
- void* sym = dlsym(mod, symb);
- dlclose(mod);
- return sym != NULL;
- }
- return false;
-}
-
-#define prep_type_name(name) name
-#endif
-
-#define _str(s) #s
-#define __str(s) _str(s)
-
-#ifndef _MOD_SUFFIX
-#ifdef WIN32
-#define _MOD_SUFFIX "dll"
-#define CR ""
-#else
-#define _MOD_SUFFIX "so"
-#define CR "\r"
-#endif
-#endif
-
-module_manager::~module_manager() {
- // Free all extensions
- for (map<string, vector<base_extension*> >::iterator i=this->extensions.begin() ; i != this->extensions.end() ; i++) {
- for (vector<base_extension*>::iterator j=i->second.begin() ; j != i->second.end() ; j++)
- delete *j;
- i->second.clear();
- }
- this->extensions.clear();
-
- // Free all modules
- for (set<void*>::iterator i=this->modules.begin() ; i != this->modules.end() ; i++)
- pdlclose(*i);
- this->modules.clear();
-}
-
-static int load(map<string, vector<base_extension*> >& extensions,
- set<string>& singletons,
- mm_module *mod,
- bool lazy,
- bool symbreq) {
- const char* debug = getenv("_MM_DEBUG");
-
- if (!mod || mod->vers != __MM_MODULE_VERSION || !mod->type || !mod->init) {
- if (debug)
- cerr << "failed!" << endl
- << "\tUnable to find basic module info!" << endl;
- return _LOAD_FAIL;
- }
-
- // Get the module type
- string types = mod->type();
-
- // Make sure the type is registered
- if (extensions.find(types) == extensions.end()) {
- if (debug)
- cerr << "failed!" << endl
- << "\tUnknown extension type: " << prep_type_name(types) << endl;
- return _LOAD_FAIL;
- }
-
- // If this is a singleton and we already have an instance, don't instantiate
- if (singletons.find(types) != singletons.end() &&
- extensions[types].size() > 0) {
- if (debug)
- cerr << "failed!" << endl
- << "\tNot loading subsequent singleton for: " << prep_type_name(types) << endl;
- return _LOAD_FAIL;
- }
-
- // If a symbol is defined, we'll search for it in the main process
- if (mod->symb && mod->smod && !pdlsymlinked(mod->smod, mod->symb)) {
- // If the symbol is not found and the symbol is required, error
- if (symbreq) {
- if (debug)
- cerr << "failed!" << endl
- << "\tUnable to find required symbol: "
- << mod->symb << endl;
- return _LOAD_FAIL;
- }
-
- // If the symbol is not found and not required, we'll load only
- // if there are no other modules of this type
- else if (extensions[types].size() > 0) {
- if (debug)
- cerr << "failed!" << endl
- << "\tUnable to find required symbol: "
- << mod->symb << endl;
- return _LOAD_FAIL;
- }
- }
-
- // We've passed all the tests this far, do it again in non-lazy mode
- if (lazy) return _LOAD_LAZY;
-
- // If our execution test succeeds, call init()
- if ((mod->test && mod->test()) || !mod->test) {
- base_extension** exts = mod->init();
- if (!exts) {
- if (debug)
- cerr << "failed!" << endl
- << "\tinit() returned no extensions!" << endl;
- return _LOAD_FAIL;
- }
-
- if (debug)
- cerr << "success" << endl;
-
- // init() returned extensions we need to register
- for (unsigned int i=0 ; exts[i] ; i++) {
- if (debug)
- cerr << "\tRegistering "
- << typeid(*exts[i]).name() << "("
- << prep_type_name(exts[i]->get_base_type()) << ")" << endl;
- extensions[exts[i]->get_base_type()].push_back(exts[i]);
- }
- delete[] exts;
- return _LOAD_SUCC;
- }
-
- if (debug)
- cerr << "failed!" << endl
- << "\tTest execution failed." << endl;
- return _LOAD_FAIL;
-}
-
-bool module_manager::load_builtin(mm_module *mod) {
- const char* debug = getenv("_MM_DEBUG");
- if (debug)
- cerr << "loading : builtin module " << mod->name << CR;
-
- // Do the load with the specified prefix
- int status = load(this->extensions, this->singletons, mod, false, false);
- return status == _LOAD_SUCC;
-}
-
-bool module_manager::load_file(const string &filename, bool symbreq) {
- const char* debug = getenv("_MM_DEBUG");
-
- // Stat the file to make sure it is a file
- struct stat st;
- if (stat(filename.c_str(), &st) != 0) return false;
- if ((st.st_mode & S_IFMT) != S_IFREG) return false;
-
- if (debug)
- cerr << "loading : " << filename << CR;
-
- // Open the module
- pdlmtype dlobj = pdlopenl(filename.c_str());
- if (!dlobj) {
- if (debug)
- cerr << "failed!" << endl
- << "\t" << pdlerror() << endl;
- return false;
- }
-
- // If we have already loaded this module, return true
- if (this->modules.find((void*) dlobj) != this->modules.end()) {
- if (debug)
- cerr << "preload" << endl;
- pdlclose(dlobj);
- return true;
- }
-
- // Try and finish the load
- struct mm_module *mod_info = (mm_module*) pdlsym(dlobj, __str(__MM_MODULE_VARNAME(info)));
- int status = load(this->extensions, this->singletons, mod_info, true, symbreq);
- if (status == _LOAD_LAZY) { // Reload the module in non-lazy mode
- dlobj = pdlreopen(filename.c_str(), dlobj);
- if (!dlobj) {
- if (debug)
- cerr << "failed!" << endl
- << "\tUnable to reload module: " << pdlerror() << endl;
- return false;
- }
- mod_info = (mm_module*) pdlsym(dlobj, __str(__MM_MODULE_VARNAME(info)));
- status = load(this->extensions, this->singletons, mod_info, false, symbreq);
- }
- if (status == _LOAD_FAIL) {
- pdlclose(dlobj);
- return false;
- }
-
- // Add the dlobject to our known modules
- this->modules.insert((void*) dlobj);
-
- // Yay, we did it!
- return true;
-}
-
-bool module_manager::load_dir(const string &dirname, bool symbreq) {
- vector<string> files;
-
-#ifdef WIN32
- WIN32_FIND_DATA fd;
- HANDLE search;
-
- string srch = dirname + "\\*." + _MOD_SUFFIX;
- search = FindFirstFile(srch.c_str(), &fd);
- if (search != INVALID_HANDLE_VALUE) {
- do {
- files.push_back(dirname + "\\" + fd.cFileName);
- } while (FindNextFile(search, &fd));
- FindClose(search);
- }
-#else
- struct dirent *ent;
-
- DIR *moduledir = opendir(dirname.c_str());
- if (moduledir) {
- while((ent = readdir(moduledir))) {
- string tmp = ent->d_name;
- if (tmp.find(_MOD_SUFFIX, tmp.size() - string(_MOD_SUFFIX).size()) != tmp.npos)
- files.push_back(dirname + "/" + tmp);
- }
- closedir(moduledir);
- }
-#endif
-
- // Perform our load alphabetically
- sort(files.begin(), files.end());
-
- // Try to do the load
- bool loaded = false;
- for (vector<string>::iterator it = files.begin() ; it != files.end() ; it++)
- loaded = this->load_file(*it, symbreq) || loaded;
- return loaded;
-}