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"
25 #include "Interface.h"
27 #include "ResourceDesc.h"
28 #include "Variables.h" // FIXME: this should be in Interface.h instead
36 #include <sys/types.h>
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
49 typedef void *(* voidvoid
)(void);
50 inline voidvoid
my_dlsym(void *handle
, const char *symbol
)
52 void *value
= dlsym(handle
,symbol
);
54 assert(sizeof(ret
)==sizeof(value
) );
55 memcpy(&ret
, &value
, sizeof(ret
) );
59 #define my_dlsym dlsym
63 #define FREE_PLUGIN( handle ) FreeLibrary( handle )
64 #define GET_PLUGIN_SYMBOL( handle, name ) GetProcAddress( handle, name )
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() )
72 PluginMgr
*PluginMgr::Get()
78 PluginMgr::PluginMgr()
82 void PluginMgr::LoadPlugins(char* pluginpath
)
84 printMessage( "PluginMgr", "Loading Plugins from ", WHITE
);
85 printf( "%s\n", pluginpath
);
88 strcpy( path
, pluginpath
);
90 std::list
< char * > files
;
91 if (! FindFiles( path
, files
))
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();
101 PathJoin( path
, pluginpath
, file
, NULL
);
102 printBracket( "PluginMgr", LIGHT_WHITE
);
103 printf( ": Loading: " );
104 textcolor( LIGHT_WHITE
);
105 printf( "%s", path
);
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
);
120 // We do not need the basename anymore now
124 if (flags
== PLF_SKIP
) {
125 printStatus( "SKIPPING", YELLOW
);
131 // Try to load the Module
133 HMODULE hMod
= LoadLibrary( path
);
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
);
141 printBracket( "ERROR", LIGHT_RED
);
142 printf( "\nCannot Load Module, Skipping...\n" );
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" );
162 if (strcmp(LibVersion(), VERSION_GEMRB
) ) {
163 printStatus( "ERROR", LIGHT_RED
);
164 printf( "Plug-in Version not valid, Skipping...\n" );
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
);
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
);
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
);
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
199 for (unsigned int i
= 0; i
< libs
.size(); i
++) {
201 FreeLibrary(libs
[i
].handle
);
203 // dlclose(libs[i].handle);
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
;
216 strcat( path
, "*.dll" );
217 if (( hFile
= ( long ) _findfirst( path
, &c_file
) ) == -1L) //If there is no file matching our search
221 files
.push_back( strdup( c_file
.name
));
222 } while (_findnext( hFile
, &c_file
) == 0);
231 PluginMgr::FindFiles( char* path
, std::list
<char*> &files
)
233 DIR* dir
= opendir( path
);
234 if (dir
== NULL
) //If we cannot open the Directory
237 struct dirent
* de
= readdir( dir
); //Lookup the first entry in the Directory
239 //If no entry exists just return
245 if (fnmatch( "*.so", de
->d_name
, 0 ) != 0) //If the current file has no ".so" extension, skip it
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
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();
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())
277 plugins
[id
] = create
;
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())
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();