Sort include order.
[gemrb.git] / gemrb / core / PluginMgr.cpp
blob59237e34c52383eb90e8f19cbecf7cae11974997
1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "PluginMgr.h"
23 #include "win32def.h"
25 #include "Interface.h"
26 #include "Plugin.h"
27 #include "ResourceDesc.h"
28 #include "Variables.h" // FIXME: this should be in Interface.h instead
30 #include <cstdio>
31 #include <cstdlib>
32 #ifdef WIN32
33 #include <io.h>
34 #include <windows.h>
35 #else
36 #include <sys/types.h>
37 #include <dirent.h>
38 #include <fnmatch.h>
39 #include <dlfcn.h>
40 #endif
42 typedef const char* (*Version_t)(void);
43 typedef const char* (*Description_t)(void);
44 typedef PluginID (*ID_t)();
45 typedef bool (* Register_t)(PluginMgr*);
47 #ifdef HAVE_FORBIDDEN_OBJECT_TO_FUNCTION_CAST
48 #include <assert.h>
49 typedef void *(* voidvoid)(void);
50 inline voidvoid my_dlsym(void *handle, const char *symbol)
52 void *value = dlsym(handle,symbol);
53 voidvoid ret;
54 assert(sizeof(ret)==sizeof(value) );
55 memcpy(&ret, &value, sizeof(ret) );
56 return ret;
58 #else
59 #define my_dlsym dlsym
60 #endif
62 #ifdef WIN32
63 #define FREE_PLUGIN( handle ) FreeLibrary( handle )
64 #define GET_PLUGIN_SYMBOL( handle, name ) GetProcAddress( handle, name )
65 #define PRINT_DLERROR
66 #else
67 #define FREE_PLUGIN( handle ) dlclose( handle )
68 #define GET_PLUGIN_SYMBOL( handle, name ) my_dlsym( handle, name )
69 #define PRINT_DLERROR printf( "%s\n", dlerror() )
70 #endif
72 PluginMgr *PluginMgr::Get()
74 static PluginMgr mgr;
75 return &mgr;
78 PluginMgr::PluginMgr()
82 void PluginMgr::LoadPlugins(char* pluginpath)
84 printMessage( "PluginMgr", "Loading Plugins from ", WHITE );
85 printf( "%s\n", pluginpath );
87 char path[_MAX_PATH];
88 strcpy( path, pluginpath );
90 std::list< char * > files;
91 if (! FindFiles( path, files ))
92 return;
94 //Iterate through all the available modules to load
95 int file_count = files.size (); // keeps track of first-pass files
96 while (! files.empty()) {
97 char* file = files.front();
98 files.pop_front();
99 file_count--;
101 PathJoin( path, pluginpath, file, NULL );
102 printBracket( "PluginMgr", LIGHT_WHITE );
103 printf( ": Loading: " );
104 textcolor( LIGHT_WHITE );
105 printf( "%s", path );
106 textcolor( WHITE );
107 printf( "..." );
110 ieDword flags = 0;
111 core->plugin_flags->Lookup (file, flags);
113 // module is sent to the back
114 if ((flags == PLF_DELAY) && (file_count >= 0)) {
115 printStatus( "DELAYING", YELLOW );
116 files.push_back( file );
117 continue;
120 // We do not need the basename anymore now
121 free( file );
123 // module is skipped
124 if (flags == PLF_SKIP) {
125 printStatus( "SKIPPING", YELLOW );
126 continue;
131 // Try to load the Module
132 #ifdef WIN32
133 HMODULE hMod = LoadLibrary( path );
134 #else
135 // Note: the RTLD_GLOBAL is necessary to export symbols to modules
136 // which python may have to dlopen (-wjp, 20060716)
137 // (to reproduce, try 'import bz2' or another .so module)
138 void* hMod = dlopen( path, RTLD_NOW | RTLD_GLOBAL );
139 #endif
140 if (hMod == NULL) {
141 printBracket( "ERROR", LIGHT_RED );
142 printf( "\nCannot Load Module, Skipping...\n" );
143 PRINT_DLERROR;
144 continue;
147 printStatus( "OK", LIGHT_GREEN );
148 //using C bindings, so we don't need to jump through extra hoops
149 //with the symbol name
150 Version_t LibVersion = ( Version_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Version" );
151 Description_t Description = ( Description_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Description" );
152 ID_t ID = ( ID_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_ID" );
153 Register_t Register = ( Register_t ) GET_PLUGIN_SYMBOL( hMod, "GemRBPlugin_Register" );
155 printMessage( "PluginMgr", "Checking Plugin Version...", WHITE );
156 if (LibVersion==NULL) {
157 printStatus( "ERROR", LIGHT_RED );
158 printf( "Invalid Plug-in, Skipping...\n" );
159 FREE_PLUGIN( hMod );
160 continue;
162 if (strcmp(LibVersion(), VERSION_GEMRB) ) {
163 printStatus( "ERROR", LIGHT_RED );
164 printf( "Plug-in Version not valid, Skipping...\n" );
165 FREE_PLUGIN( hMod );
166 continue;
169 PluginDesc desc = { hMod, ID(), Description(), Register };
171 printStatus( "OK", LIGHT_GREEN );
172 printMessage( "PluginMgr", "Loading Exports for ", WHITE );
173 textcolor( LIGHT_WHITE );
174 printf( "%s", desc.Description );
175 textcolor( WHITE );
176 printf( "..." );
177 printStatus( "OK", LIGHT_GREEN );
178 if (libs.find(desc.ID) != libs.end()) {
179 printMessage( "PluginMgr", "Plug-in Already Loaded! ", WHITE );
180 printStatus( "SKIPPING", YELLOW );
181 FREE_PLUGIN( hMod );
182 continue;
184 if (desc.Register != NULL) {
185 if (!desc.Register(this)) {
186 printMessage( "PluginMgr", "Plug-in Registration Failed! Perhaps a duplicate? ", WHITE );
187 printStatus( "SKIPPING", YELLOW );
188 FREE_PLUGIN( hMod );
191 libs[desc.ID] = desc;
195 PluginMgr::~PluginMgr(void)
197 //don't free the shared libraries in debug mode, so valgrind can resolve the stack trace
198 #ifndef _DEBUG
199 for (unsigned int i = 0; i < libs.size(); i++) {
200 #ifdef WIN32
201 FreeLibrary(libs[i].handle);
202 #else
203 // dlclose(libs[i].handle);
204 #endif
206 #endif
209 #ifdef WIN32
210 bool
211 PluginMgr::FindFiles( char* path, std::list<char*> &files )
213 //The windows _findfirst/_findnext functions allow the use of wildcards so we'll use them :)
214 struct _finddata_t c_file;
215 long hFile;
216 strcat( path, "*.dll" );
217 if (( hFile = ( long ) _findfirst( path, &c_file ) ) == -1L) //If there is no file matching our search
218 return false;
220 do {
221 files.push_back( strdup( c_file.name ));
222 } while (_findnext( hFile, &c_file ) == 0);
224 _findclose( hFile );
225 return true;
228 #else // ! WIN32
230 bool
231 PluginMgr::FindFiles( char* path, std::list<char*> &files )
233 DIR* dir = opendir( path );
234 if (dir == NULL) //If we cannot open the Directory
235 return false;
237 struct dirent* de = readdir( dir ); //Lookup the first entry in the Directory
238 if (de == NULL) {
239 //If no entry exists just return
240 closedir( dir );
241 return false;
244 do {
245 if (fnmatch( "*.so", de->d_name, 0 ) != 0) //If the current file has no ".so" extension, skip it
246 continue;
247 files.push_back( strdup( de->d_name ));
248 } while (( de = readdir( dir ) ) != NULL);
250 closedir( dir ); //No other files in the directory, close it
251 return true;
253 #endif // ! WIN32
255 bool PluginMgr::IsAvailable(SClass_ID plugintype) const
257 return plugins.find(plugintype) != plugins.end();
260 Plugin* PluginMgr::GetPlugin(SClass_ID plugintype) const
262 std::map<SClass_ID, PluginFunc>::const_iterator iter = plugins.find(plugintype);
263 if (iter != plugins.end())
264 return iter->second();
265 return NULL;
268 const std::vector<ResourceDesc>& PluginMgr::GetResourceDesc(const TypeID* type)
270 return resources[type];
273 bool PluginMgr::RegisterPlugin(SClass_ID id, PluginFunc create)
275 if (plugins.find(id) != plugins.end())
276 return false;
277 plugins[id] = create;
278 return true;
281 void PluginMgr::RegisterResource(const TypeID* type, ResourceFunc create, const char *ext, ieWord keyType)
283 resources[type].push_back(ResourceDesc(type,create,ext,keyType));
286 void PluginMgr::RegisterInitializer(void (*func)(void))
288 intializerFunctions.push_back(func);
291 void PluginMgr::RegisterCleanup(void (*func)(void))
293 cleanupFunctions.push_back(func);
296 void PluginMgr::RunInitializers() const
298 for (size_t i = 0; i < intializerFunctions.size(); i++)
299 intializerFunctions[i]();
302 void PluginMgr::RunCleanup() const
304 for (size_t i = 0; i < cleanupFunctions.size(); i++)
305 cleanupFunctions[i]();
308 bool PluginMgr::RegisterDriver(const TypeID* type, const char* name, PluginFunc create)
310 driver_map &map = drivers[type];
311 driver_map::const_iterator iter = map.find(name);
312 if (iter != map.end())
313 return false;
314 map[name] = create;
315 return true;
318 Plugin* PluginMgr::GetDriver(const TypeID* type, const char* name)
320 driver_map &map = drivers[type];
321 driver_map::const_iterator iter = map.find(name);
322 if (iter != map.end())
323 return iter->second();
324 return map.begin()->second();