ok
[xonotic/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, 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(__linux__) || defined (__APPLE__)
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 #endif
202
203 class DynamicLibraryModule
204 {
205   typedef void (RADIANT_DLLEXPORT* RegisterModulesFunc)(ModuleServer& server);
206   DynamicLibrary m_library;
207   RegisterModulesFunc m_registerModule;
208 public:
209   DynamicLibraryModule(const char* filename)
210     : m_library(filename), m_registerModule(0)
211   {
212     if(!m_library.failed())
213     {
214       m_registerModule = reinterpret_cast<RegisterModulesFunc>(m_library.findSymbol("Radiant_RegisterModules"));
215     }
216   }
217   bool failed()
218   {
219     return m_registerModule == 0;
220   }
221   void registerModules(ModuleServer& server)
222   {
223     m_registerModule(server);
224   }
225 };
226
227
228 class Libraries
229 {
230   typedef std::vector<DynamicLibraryModule*> libraries_t;
231   libraries_t m_libraries;
232
233 public:
234   ~Libraries()
235   {
236     release();
237   }
238   void registerLibrary(const char* filename, ModuleServer& server)
239   {
240     DynamicLibraryModule* library = new DynamicLibraryModule(filename);
241
242     if(library->failed())
243     {
244       delete library;
245     }
246     else
247     {
248       m_libraries.push_back(library);
249       library->registerModules(server);
250     }
251   }
252   void release()
253   {
254     for(libraries_t::iterator i = m_libraries.begin(); i != m_libraries.end(); ++i)
255     {
256       delete *i;
257     }
258   }
259   void clear()
260   {
261     m_libraries.clear();
262   }
263 };
264
265
266 Libraries g_libraries;
267 RadiantModuleServer g_server;
268
269 ModuleServer& GlobalModuleServer_get()
270 {
271   return g_server;
272 }
273
274 void GlobalModuleServer_loadModule(const char* filename)
275 {
276   g_libraries.registerLibrary(filename, g_server);
277 }
278
279 void GlobalModuleServer_Initialise()
280 {
281 }
282
283 void GlobalModuleServer_Shutdown()
284 {
285 }