/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant 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 GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(INCLUDED_MODULESYSTEM_H) #define INCLUDED_MODULESYSTEM_H #include "generic/static.h" #include "debugging/debugging.h" #if defined(WIN32) #define RADIANT_DLLEXPORT __stdcall #else #define RADIANT_DLLEXPORT #endif class Module { public: virtual void capture() = 0; virtual void release() = 0; virtual void* getTable() = 0; }; inline void* Module_getTable(Module& module) { return module.getTable(); } class TextOutputStream; class DebugMessageHandler; class ModuleServer { public: class Visitor { public: virtual void visit(const char* name, Module& module) const = 0; }; virtual void setError(bool error) = 0; virtual bool getError() const = 0; virtual TextOutputStream& getOutputStream() = 0; virtual TextOutputStream& getErrorStream() = 0; virtual DebugMessageHandler& getDebugMessageHandler() = 0; virtual void registerModule(const char* type, int version, const char* name, Module& module) = 0; virtual Module* findModule(const char* type, int version, const char* name) const = 0; virtual void foreachModule(const char* type, int version, const Visitor& visitor) = 0; }; class ModuleServerHolder { ModuleServer* m_server; public: ModuleServerHolder() : m_server(0) { } void set(ModuleServer& server) { m_server = &server; } ModuleServer& get() { return *m_server; } }; typedef Static GlobalModuleServer; inline ModuleServer& globalModuleServer() { return GlobalModuleServer::instance().get(); } inline void initialiseModule(ModuleServer& server) { GlobalErrorStream::instance().setOutputStream(server.getErrorStream()); GlobalOutputStream::instance().setOutputStream(server.getOutputStream()); GlobalDebugMessageHandler::instance().setHandler(server.getDebugMessageHandler()); GlobalModuleServer::instance().set(server); } template class Modules { public: class Visitor { public: virtual void visit(const char* name, const Type& table) const = 0; }; virtual Type* findModule(const char* name) = 0; virtual void foreachModule(const Visitor& visitor) = 0; }; #include "debugging/debugging.h" template class ModuleRef { Module* m_module; Type* m_table; public: ModuleRef(const char* name) : m_table(0) { if(!globalModuleServer().getError()) { m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name); if(m_module == 0) { globalModuleServer().setError(true); globalErrorStream() << "ModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n"; } else { m_module->capture(); if(!globalModuleServer().getError()) { m_table = static_cast(m_module->getTable()); } } } } ~ModuleRef() { if(m_module != 0) { m_module->release(); } } Type* getTable() { #if defined(_DEBUG) ASSERT_MESSAGE(m_table != 0, "ModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised"); #endif return m_table; } }; template class SingletonModuleRef { Module* m_module; Type* m_table; public: SingletonModuleRef() : m_module(0), m_table(0) { } bool initialised() const { return m_module != 0; } void initialise(const char* name) { m_module = globalModuleServer().findModule(typename Type::Name(), typename Type::Version(), name); if(m_module == 0) { globalModuleServer().setError(true); globalErrorStream() << "SingletonModuleRef::initialise: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " name=" << makeQuoted(name) << " - not found\n"; } } Type* getTable() { #if defined(_DEBUG) ASSERT_MESSAGE(m_table != 0, "SingletonModuleRef::getTable: type=" << makeQuoted(typename Type::Name()) << " version=" << makeQuoted(typename Type::Version()) << " - module-reference used without being initialised"); #endif return m_table; } void capture() { if(initialised()) { m_module->capture(); m_table = static_cast(m_module->getTable()); } } void release() { if(initialised()) { m_module->release(); } } }; template class GlobalModule { static SingletonModuleRef m_instance; public: static SingletonModuleRef& instance() { return m_instance; } static Type& getTable() { return *m_instance.getTable(); } }; template SingletonModuleRef GlobalModule::m_instance; template class GlobalModuleRef { public: GlobalModuleRef(const char* name = "*") { if(!globalModuleServer().getError()) { GlobalModule::instance().initialise(name); } GlobalModule::instance().capture(); } ~GlobalModuleRef() { GlobalModule::instance().release(); } Type& getTable() { return GlobalModule::getTable(); } }; #endif