git-svn-id: svn://svn.icculus.org/netradiant/trunk@54 61c419a2-8eb2-4b30-bcec-8cead03...
[divverent/netradiant.git] / radiant / server.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "server.h"
23
24 #include "debugging/debugging.h"
25 #include "warnings.h"
26
27 #include <vector>
28 #include <map>
29 #include "os/path.h"
30
31 #include "modulesystem.h"
32
33 class RadiantModuleServer : public ModuleServer
34 {
35   typedef std::pair<CopiedString, int> ModuleType;
36   typedef std::pair<ModuleType, CopiedString> ModuleKey;
37   typedef std::map<ModuleKey, Module*> Modules_;
38   Modules_ m_modules;
39   bool m_error;
40
41 public:
42   RadiantModuleServer() : m_error(false)
43   {
44   }
45
46   void setError(bool error)
47   {
48     m_error = error;
49   }
50   bool getError() const
51   {
52     return m_error;
53   }
54
55   TextOutputStream& getOutputStream()
56   {
57     return globalOutputStream();
58   }
59   TextOutputStream& getErrorStream()
60   {
61     return globalErrorStream();
62   }
63   DebugMessageHandler& getDebugMessageHandler()
64   {
65     return globalDebugMessageHandler();
66   }
67
68   void registerModule(const char* type, int version, const char* name, Module& module)
69   {
70     ASSERT_NOTNULL(&module);
71     if(!m_modules.insert(Modules_::value_type(ModuleKey(ModuleType(type, version), name), &module)).second)
72     {
73       globalErrorStream() << "module already registered: type=" << makeQuoted(type) << " name=" << makeQuoted(name) << "\n";
74     }
75     else
76     {
77       globalOutputStream() << "Module Registered: type=" << makeQuoted(type) << " version=" << makeQuoted(version) << " name=" << makeQuoted(name) << "\n";
78     }
79   }
80
81   Module* findModule(const char* type, int version, const char* name) const
82   {
83     Modules_::const_iterator i = m_modules.find(ModuleKey(ModuleType(type, version), name));
84     if(i != m_modules.end())
85     {
86       return (*i).second;
87     }
88     return 0;
89   }
90
91   void foreachModule(const char* type, int version, const Visitor& visitor)
92   {
93     for(Modules_::const_iterator i = m_modules.begin(); i != m_modules.end(); ++i)
94     {
95       if(string_equal((*i).first.first.first.c_str(), type))
96       {
97         visitor.visit((*i).first.second.c_str(), *(*i).second);
98       }
99     }
100   }
101 };
102
103
104 #if defined(WIN32)
105
106 #include <windows.h>
107
108 #define FORMAT_BUFSIZE 2048
109 const char* FormatGetLastError()
110 {
111   static char buf[FORMAT_BUFSIZE];
112   FormatMessage(
113     FORMAT_MESSAGE_FROM_SYSTEM | 
114     FORMAT_MESSAGE_IGNORE_INSERTS,
115     NULL,
116     GetLastError(),
117     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
118     buf,
119     FORMAT_BUFSIZE,
120     NULL 
121   );
122   return buf;
123 }
124
125 class DynamicLibrary
126 {
127   HMODULE m_library;
128 public:
129   typedef int (__stdcall* FunctionPointer)();
130
131   DynamicLibrary(const char* filename)
132   {
133     m_library = LoadLibrary(filename);
134     if(m_library == 0)
135     {
136       globalErrorStream() << "LoadLibrary failed: '" << filename << "'\n";
137       globalErrorStream() << "GetLastError: " << FormatGetLastError();
138     }
139   }
140   ~DynamicLibrary()
141   {
142     if(!failed())
143     {
144       FreeLibrary(m_library);
145     }
146   }
147   bool failed()
148   {
149     return m_library == 0;
150   }
151   FunctionPointer findSymbol(const char* symbol)
152   {
153     FunctionPointer address = GetProcAddress(m_library, symbol);
154     if(address == 0)
155     {
156       globalErrorStream() << "GetProcAddress failed: '" << symbol << "'\n";
157       globalErrorStream() << "GetLastError: " << FormatGetLastError();
158     }
159     return address;
160   }
161 };
162
163 #elif defined(POSIX)
164
165 #include <dlfcn.h>
166
167 class DynamicLibrary
168 {
169   void* m_library;
170 public:
171   typedef int (* FunctionPointer)();
172
173   DynamicLibrary(const char* filename)
174   {
175     m_library = dlopen(filename, RTLD_NOW);
176   }
177   ~DynamicLibrary()
178   {
179     if(!failed())
180       dlclose(m_library);
181   }
182   bool failed()
183   {
184     return m_library == 0;
185   }
186   FunctionPointer findSymbol(const char* symbol)
187   {
188     FunctionPointer p = (FunctionPointer)dlsym(m_library, symbol);
189     if(p == 0)
190     {
191       const char* error = reinterpret_cast<const char*>(dlerror());
192       if(error != 0)
193       {
194         globalErrorStream() << error;
195       }
196     }
197     return p;
198   }
199 };
200
201 #else
202 #error "unsupported platform"
203 #endif
204
205 class DynamicLibraryModule
206 {
207   typedef void (RADIANT_DLLIMPORT* RegisterModulesFunc)(ModuleServer& server);
208   DynamicLibrary m_library;
209   RegisterModulesFunc m_registerModule;
210 public:
211   DynamicLibraryModule(const char* filename)
212     : m_library(filename), m_registerModule(0)
213   {
214     if(!m_library.failed())
215     {
216       m_registerModule = reinterpret_cast<RegisterModulesFunc>(m_library.findSymbol("Radiant_RegisterModules"));
217 #if 0
218       if(!m_registerModule)
219               m_registerModule = reinterpret_cast<RegisterModulesFunc>(m_library.findSymbol("Radiant_RegisterModules@4"));
220 #endif
221     }
222   }
223   bool failed()
224   {
225     return m_registerModule == 0;
226   }
227   void registerModules(ModuleServer& server)
228   {
229     m_registerModule(server);
230   }
231 };
232
233
234 class Libraries
235 {
236   typedef std::vector<DynamicLibraryModule*> libraries_t;
237   libraries_t m_libraries;
238
239 public:
240   ~Libraries()
241   {
242     release();
243   }
244   void registerLibrary(const char* filename, ModuleServer& server)
245   {
246     DynamicLibraryModule* library = new DynamicLibraryModule(filename);
247
248     if(library->failed())
249     {
250       delete library;
251     }
252     else
253     {
254       m_libraries.push_back(library);
255       library->registerModules(server);
256     }
257   }
258   void release()
259   {
260     for(libraries_t::iterator i = m_libraries.begin(); i != m_libraries.end(); ++i)
261     {
262       delete *i;
263     }
264   }
265   void clear()
266   {
267     m_libraries.clear();
268   }
269 };
270
271
272 Libraries g_libraries;
273 RadiantModuleServer g_server;
274
275 ModuleServer& GlobalModuleServer_get()
276 {
277   return g_server;
278 }
279
280 void GlobalModuleServer_loadModule(const char* filename)
281 {
282   g_libraries.registerLibrary(filename, g_server);
283 }
284
285 void GlobalModuleServer_Initialise()
286 {
287 }
288
289 void GlobalModuleServer_Shutdown()
290 {
291 }