/* * Velcro Module Language * Copyright (c) 2006, Carsten Valdemar Munk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * The name of Carsten Valdemar Munk may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $Id$ */ @version $Id$ @copyright (C) Copyright 2006 Carsten Valdemar Munk #include #include #include typedef void *(VoidFunctionPointer) (void); typedef void *(VoidIntParaFunctionPointer) (int value); typedef void *(VoidIntPointerParaFunctionPointer) (int *ret); class Velcro { public: bool dependsOnModule(const char *who, const char *module); @hook initialStartup(); static Velcro& instanceOf() { static Velcro modules; return modules; } std::list modulesLoading; std::list modulesLoaded; std::map modules; bool isModuleLoaded(const char *module); bool isModuleLoading(const char *module); }; implementation: #include // Glue for Unreal3 extern "C" { #include "config.h" #include "struct.h" #include "common.h" #include "sys.h" #include "numeric.h" #include "msg.h" #include "proto.h" #include "channel.h" #include #include #include #include #include #ifdef _WIN32 #include #endif #include #include "h.h" #ifdef STRIPBADWORDS #include "badwords.h" #endif #ifdef _WIN32 #include "version.h" #endif } ModuleHeader MOD_HEADER(Velcro) = { "Velcro", "$Id$", "Velcro module system", "3.2-b8-1", NULL }; static Hook *HookConfTest = NULL; static Hook *HookConfRun = NULL; static Hook *HookConfRehash = NULL; DLLFUNC int h_velcro_configtest(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) { ConfigEntry *cep; int errors = 0; if(type != CONFIG_MAIN) return 0; if(!strcmp(ce->ce_varname, "loadmodule4")) { if (!ce->ce_vardata) { config_status("%s:%i: loadmodule4 without filename", ce->ce_fileptr->cf_filename, ce->ce_varlinenum); errors=1; *errs=errors; return -1; } return 1; } return 0; } DLLFUNC int h_velcro_configrun(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) { ConfigEntry *cep; int errors = 0; if(type != CONFIG_MAIN) return 0; if(!strcmp(ce->ce_varname, "loadmodule4")) { config_status("%s:%i: loadmodule4: %s", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, ce->ce_vardata); Velcro::instanceOf().dependsOnModule("Velcro", ce->ce_vardata); return 1; } return 0; } DLLFUNC int h_velcro_configrehash() { return 0; } extern "C" DLLFUNC int MOD_INIT(Velcro)(ModuleInfo *modinfo) { MARK_AS_OFFICIAL_MODULE(modinfo); ModuleSetOptions(modinfo->handle, MOD_OPT_PERM); HookConfRun = HookAddCfg(modinfo->handle, HOOKTYPE_CONFIGRUN, h_velcro_configrun); HookConfRehash = HookAddEx(modinfo->handle, HOOKTYPE_REHASH, h_velcro_configrehash); config_status("velcro init"); return MOD_SUCCESS; } extern "C" DLLFUNC int MOD_TEST(Velcro)(ModuleInfo *modinfo) { config_status("velcro test"); HookConfTest = HookAddCfg(modinfo->handle, HOOKTYPE_CONFIGTEST, h_velcro_configtest); return MOD_SUCCESS; } extern "C" DLLFUNC int MOD_LOAD(Velcro)(int module_load) { Velcro_init(false); config_status("velcro load"); return MOD_SUCCESS; } extern "C" DLLFUNC int MOD_UNLOAD(Velcro)(int module_unload) { config_status("velcro unload"); return MOD_FAILED; } // Actual Velcro @on this_Module::onInit(bool reloading) { @yield; } @on this_Module::onUnload() { @yield; } @on this_Module::onReload() { @yield; } bool Velcro::dependsOnModule(const char *who, const char *module) { char buf[1024]; std::string ms = module; if (isModuleLoaded(module)) return true; // Already loaded if (isModuleLoading(module)) { config_error("Velcro: Error loading dependancy %s for %s: module is currently being loaded - Circle dependancy?", module, who); return false; } modulesLoading.push_back(ms); config_status("Loading module %s as a dependancy of %s", module, who); snprintf(buf, 1024, "u4modules/%s.so", module); void *dl = dlopen(buf, RTLD_LAZY|RTLD_LOCAL); if (dl == NULL) { config_status("Velcro: Error loading dependancy %s for %s: %s, possible error/RTLD_LAZY broken, trying old fashioned dependancy loading and trying again afterwards", module, who, dlerror()); snprintf(buf, 1024, "u4modules/%s.depends", module); FILE *f = fopen(buf, "r"); if (f == NULL) { config_error("Velcro: Error opening depends file for %s: %s", module, strerror(errno)); return false; } char *ss; while ((ss = fgets(buf, 1023, f)) != NULL) { char *p = strchr(ss, '\r'); if (p != NULL) *p = 0; p = strchr(ss, '\n'); if (p != NULL) *p = 0; if (*ss == 0) continue; if (!dependsOnModule(module, ss)) return false; } } else { snprintf(buf, 1024, "%s_checkDepends", module); VoidIntPointerParaFunctionPointer *depend = (VoidIntPointerParaFunctionPointer *) dlsym(dl, buf); if (depend == NULL) { config_error("Velcro: Error loading dependancy %s for %s: Unable to find %s_checkDepends", module, who, module); return false; } // kludge.. no idea why it doesn't work with int * int ret = 0; (*depend)(&ret); if (ret == -1) { dlclose(dl); return false; } dlclose(dl); } /* now done loading dependancies, reopen with RTLD_GLOBAL|RTLD_NOW .. */ snprintf(buf, 1024, "u4modules/%s.so", module); dl = dlopen(buf, RTLD_GLOBAL|RTLD_NOW); if (dl == NULL) { config_error("Velcro: Error loading reopening dependancy %s for %s: %s", module, who, dlerror()); return false; } snprintf(buf, 1024, "%s_init", module); VoidIntParaFunctionPointer *init = (VoidIntParaFunctionPointer *)dlsym(dl, buf); if (init == NULL) { config_error("Velcro: Error loading dependancy %s for %s: Unable to find %s_init" , module, who, module); return false; } modulesLoading.remove(ms); modulesLoaded.push_back(ms); modules[ms] = dl; (*init)(false); { config_status("Velcro: Loaded module %s as dependancy of %s", module, who); } return true; } bool Velcro::isModuleLoaded(const char *moduleName) { std::string module = moduleName; std::list::iterator it = modulesLoaded.begin(); while (it != modulesLoaded.end()) { if (module == (*it)) return true; it++; } return false; } bool Velcro::isModuleLoading(const char *moduleName) { std::string module = moduleName; std::list::iterator it = modulesLoading.begin(); while (it != modulesLoading.end()) { if (module == (*it)) return true; it++; } return false; }