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 );
174 textcolor( LIGHT_WHITE
);
175 printf( "%s", desc
.Description
);
178 printStatus( "OK", LIGHT_GREEN
);
179 if (libs
.find(desc
.ID
) != libs
.end()) {
180 printMessage( "PluginMgr", "Plug-in Already Loaded! ", WHITE
);
181 printStatus( "SKIPPING", YELLOW
);
185 if (desc
.Register
!= NULL
) {
186 if (!desc
.Register(this)) {
187 printMessage( "PluginMgr", "Plug-in Registration Failed! Perhaps a duplicate? ", WHITE
);
188 printStatus( "SKIPPING", YELLOW
);
192 libs
[desc
.ID
] = desc
;
196 PluginMgr::~PluginMgr(void)
198 //don't free the shared libraries in debug mode, so valgrind can resolve the stack trace
200 for (unsigned int i
= 0; i
< libs
.size(); i
++) {
202 FreeLibrary(libs
[i
].handle
);
204 // dlclose(libs[i].handle);
212 PluginMgr::FindFiles( char* path
, std::list
<char*> &files
)
214 //The windows _findfirst/_findnext functions allow the use of wildcards so we'll use them :)
215 struct _finddata_t c_file
;
217 strcat( path
, "*.dll" );
218 if (( hFile
= ( long ) _findfirst( path
, &c_file
) ) == -1L) //If there is no file matching our search
222 files
.push_back( strdup( c_file
.name
));
223 } while (_findnext( hFile
, &c_file
) == 0);
232 PluginMgr::FindFiles( char* path
, std::list
<char*> &files
)
234 DirectoryIterator
dir(path
);
235 if (!dir
) //If we cannot open the Directory
239 const char *name
= dir
.GetName();
240 if (fnmatch( "*.so", name
, 0 ) != 0) //If the current file has no ".so" extension, skip it
242 files
.push_back( strdup( name
));
249 bool PluginMgr::IsAvailable(SClass_ID plugintype
) const
251 return plugins
.find(plugintype
) != plugins
.end();
254 Plugin
* PluginMgr::GetPlugin(SClass_ID plugintype
) const
256 std::map
<SClass_ID
, PluginFunc
>::const_iterator iter
= plugins
.find(plugintype
);
257 if (iter
!= plugins
.end())
258 return iter
->second();
262 const std::vector
<ResourceDesc
>& PluginMgr::GetResourceDesc(const TypeID
* type
)
264 return resources
[type
];
267 bool PluginMgr::RegisterPlugin(SClass_ID id
, PluginFunc create
)
269 if (plugins
.find(id
) != plugins
.end())
271 plugins
[id
] = create
;
275 void PluginMgr::RegisterResource(const TypeID
* type
, ResourceFunc create
, const char *ext
, ieWord keyType
)
277 resources
[type
].push_back(ResourceDesc(type
,create
,ext
,keyType
));
280 void PluginMgr::RegisterInitializer(void (*func
)(void))
282 intializerFunctions
.push_back(func
);
285 void PluginMgr::RegisterCleanup(void (*func
)(void))
287 cleanupFunctions
.push_back(func
);
290 void PluginMgr::RunInitializers() const
292 for (size_t i
= 0; i
< intializerFunctions
.size(); i
++)
293 intializerFunctions
[i
]();
296 void PluginMgr::RunCleanup() const
298 for (size_t i
= 0; i
< cleanupFunctions
.size(); i
++)
299 cleanupFunctions
[i
]();
302 bool PluginMgr::RegisterDriver(const TypeID
* type
, const char* name
, PluginFunc create
)
304 driver_map
&map
= drivers
[type
];
305 driver_map::const_iterator iter
= map
.find(name
);
306 if (iter
!= map
.end())
312 Plugin
* PluginMgr::GetDriver(const TypeID
* type
, const char* name
)
314 driver_map
&map
= drivers
[type
];
315 if (map
.begin() == map
.end())
317 driver_map::const_iterator iter
= map
.find(name
);
318 if (iter
!= map
.end())
319 return iter
->second();
320 return map
.begin()->second();