summaryrefslogtreecommitdiff
path: root/src/stable/plugger.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/plugger.h')
-rw-r--r--src/stable/plugger.h289
1 files changed, 289 insertions, 0 deletions
diff --git a/src/stable/plugger.h b/src/stable/plugger.h
new file mode 100644
index 0000000..c22f964
--- /dev/null
+++ b/src/stable/plugger.h
@@ -0,0 +1,289 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_PLUGGER_H
9#define BU_PLUGGER_H
10
11#include "bu/hash.h"
12#include "bu/list.h"
13#include "bu/exceptionbase.h"
14#include "bu/string.h"
15#include <stddef.h>
16
17#include "bu/config.h"
18
19#ifdef WIN32
20# include <windows.h>
21#else
22# include <dlfcn.h>
23#endif
24
25namespace Bu
26{
27 subExceptionDecl( PluginException );
28
29 typedef struct PluginInfo
30 {
31 const char *sID;
32 const char *sAuthor;
33 unsigned short nVersion;
34 unsigned short nRevision;
35 void *(*createPlugin)();
36 void (*destroyPlugin)( void * );
37 } PluginInfo;
38
39 typedef struct PluginReg
40 {
41 bool bBuiltin;
42#ifdef WIN32
43 HMODULE dlHandle;
44#else
45 void *dlHandle;
46#endif
47 PluginInfo *pInfo;
48 } PluginReg;
49
50#define PluginInterface( classname, baseclass, name, ver, rev ) \
51 extern "C" { \
52 baseclass *create ##classname() \
53 { \
54 return new classname(); \
55 } \
56 void destroy ##classname( baseclass *pCls ) \
57 { \
58 delete pCls; \
59 } \
60 Bu::PluginInfo classname = { \
61 #classname, name, ver, rev, \
62 create ##classname, destroy ##classname }; \
63 }
64
65#define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \
66 extern "C" { \
67 baseclass *create ##classname() \
68 { \
69 return new classname(); \
70 } \
71 void destroy ##classname( baseclass *pCls ) \
72 { \
73 delete pCls; \
74 } \
75 Bu::PluginInfo pluginname = { \
76 #pluginname, name, ver, rev, \
77 (void *(*)())(create ##classname), \
78 (void (*)( void * ))(destroy ##classname) }; \
79 }
80
81//
82// This is probably the main interface to use, I'll describe it some here...
83// structname - The name of the structure, this is what you have to pass to
84// register. Depending on how you build your dll/so files this
85// will need to be unique (generally not)
86// pluginname - This is what will be used by the plugin system to refer to
87// your plugin once it's loaded. This should be unique, but not
88// a string
89// classname - The name of the class that is the plugin
90// baseclass - The name of the base class that is the parent of the plugin
91// name - The name of the author of this class (or company)
92// ver - an integer version number for the plugin
93// rev - an integer revision number for the plugin
94//
95#define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \
96 extern "C" { \
97 baseclass *create ##classname() \
98 { \
99 return new classname(); \
100 } \
101 void destroy ##classname( baseclass *pCls ) \
102 { \
103 delete pCls; \
104 } \
105 Bu::PluginInfo structname = { \
106 #pluginname, name, ver, rev, \
107 (void *(*)())(create ##classname), \
108 (void (*)( void * ))(destroy ##classname) }; \
109 }
110
111 /**
112 * A complete dynamic plugin manager system. This will allow you to design
113 * and use plugins that are compiled into your program and dynamically
114 * linked to your program interchangably. It works on windows and on *nix
115 * and bsd type systems (anything that supports dlopen). Basically you
116 * create a base class that will be the basic interface of your plugins.
117 * Then you create some classes that inherit from it, and use the
118 * PluginInterface3 macro to create the required data structures for it.
119 *
120 * Once you have plugins you can create a Plugger, by passing in the base
121 * class as it's template parameter. Once it's created, you can register
122 * plugins. To register a plugin that is builtin, you just need to pass
123 * a pointer to it's interface structure to the registerBuiltinPlugin
124 * function. To register a plugin that is in a shared object or dll file
125 * you just pass the filename (with path, probably), and the name of the
126 * structure to load and you're all set.
127 *
128 * To instantiate an object from a plugin simply call instantiate with the
129 * name of the plugin as specified in the interface macro. To destroy an
130 * object crated with the plugger do not delete it, instead pass it into
131 * Plugger's destroy function.
132 *
133 * Any objects not destroyed when the plugger is deleted will be destroyed
134 * automatically.
135 *
136 * It is important to note that some systems (linux at least) partition off
137 * the memory allocated by objects linked in at run time into a seperate
138 * segment that, while it can be accessed by the main program, cannot be
139 * safely or reliably freed by the main program. With that in mind it is
140 * a good idea to free all memory allocated by a plugin object in the plugin
141 * object and not allow the calling program to delete it.
142 */
143 template<class T>
144 class Plugger
145 {
146 public:
147 typedef Bu::Hash<Bu::String, PluginReg *> PluginHash;
148 typedef Bu::Hash<ptrdiff_t, void *> InstHash;
149
150 public:
151 Plugger()
152 {
153 }
154
155 virtual ~Plugger()
156 {
157 for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ )
158 {
159 T *pPlug = (T *)i.getKey();
160 PluginReg *pReg = (PluginReg *)*i;
161 pReg->pInfo->destroyPlugin( pPlug );
162 }
163
164 for( PluginHash::iterator i = hPlugin.begin();
165 i != hPlugin.end(); i++ )
166 {
167 if( (*i)->bBuiltin == false )
168 {
169#ifdef WIN32
170 FreeLibrary( (*i)->dlHandle );
171#else
172 dlclose( (*i)->dlHandle );
173#endif
174 }
175 delete (*i);
176 }
177 }
178
179 void registerBuiltinPlugin( PluginInfo *pInfo )
180 {
181 PluginReg *pReg = new PluginReg;
182 pReg->bBuiltin = true;
183 pReg->pInfo = pInfo;
184 hPlugin.insert( pInfo->sID, pReg );
185 }
186
187 void registerExternalPlugin( const Bu::String &sFName,
188 const Bu::String &sPluginName )
189 {
190 PluginReg *pReg;
191 if( hPlugin.has( sPluginName ) )
192 throw Bu::ExceptionBase("A plugin with name '%s' is already "
193 "loaded.", sPluginName.getStr() );
194
195 pReg = new PluginReg;
196
197 pReg->bBuiltin = false;
198#ifdef WIN32
199 pReg->dlHandle = LoadLibrary( sFName.getStr() );
200 if( pReg->dlHandle == NULL )
201 {
202 throw PluginException( 1, "Error opening %s: %s",
203 sFName.getStr(), Bu::getLastWinError().getStr() );
204 }
205 pReg->pInfo = (PluginInfo *)GetProcAddress( pReg->dlHandle,
206 sPluginName.getStr() );
207 if( pReg->pInfo == NULL )
208 {
209 throw PluginException( 2, "Error mapping %s: %s",
210 sFName.getStr(), Bu::getLastWinError().getStr() );
211 }
212#else
213 pReg->dlHandle = dlopen( sFName.getStr(), RTLD_NOW );
214 if( pReg->dlHandle == NULL )
215 {
216 throw PluginException( 1, "Error opening %s: %s",
217 sFName.getStr(), dlerror() );
218 }
219 pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle,
220 sPluginName.getStr() );
221 if( pReg->pInfo == NULL )
222 {
223 throw PluginException( 2, "Error mapping %s: %s",
224 sFName.getStr(), dlerror() );
225 }
226#endif
227 hPlugin.insert( pReg->pInfo->sID, pReg );
228 }
229
230 T *instantiate( const Bu::String &lpName )
231 {
232 PluginReg *pReg = (PluginReg *)hPlugin[lpName];
233 if( pReg == NULL )
234 return NULL;
235
236 T *p = (T *)pReg->pInfo->createPlugin();
237 hObj.insert( (ptrdiff_t)p, pReg );
238 //printf("pReg: %08X, pPlug: %08X\n", pReg, p );
239
240 return p;
241 }
242
243 bool hasPlugin( const Bu::String &lpName )
244 {
245 return hPlugin.has( lpName );
246 }
247
248 void destroy( T *pPlug )
249 {
250 PluginReg *pReg = (PluginReg *)hObj.get((ptrdiff_t)pPlug);
251 //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug );
252 if( pReg == NULL )
253 return;
254
255 pReg->pInfo->destroyPlugin( pPlug );
256
257 hObj.erase( (ptrdiff_t)pPlug );
258 }
259
260 void unloadAll()
261 {
262 for( PluginHash::iterator i = hPlugin.begin();
263 i != hPlugin.end(); i++ )
264 {
265 if( (*i)->bBuiltin == false )
266 {
267#ifdef WIN32
268 FreeLibrary( (*i)->dlHandle );
269#else
270 dlclose( (*i)->dlHandle );
271#endif
272 }
273 delete (*i);
274 }
275 hPlugin.clear();
276 }
277
278 Bu::List<Bu::String> getPluginList()
279 {
280 return hPlugin.getKeys();
281 }
282
283 private:
284 PluginHash hPlugin;
285 InstHash hObj;
286 };
287}
288
289#endif