diff options
Diffstat (limited to 'src/plugger.h')
-rw-r--r-- | src/plugger.h | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/src/plugger.h b/src/plugger.h new file mode 100644 index 0000000..98d4ecc --- /dev/null +++ b/src/plugger.h | |||
@@ -0,0 +1,196 @@ | |||
1 | #ifndef PLUGGER_H | ||
2 | #define PLUGGER_H | ||
3 | |||
4 | |||
5 | #include "bu/hash.h" | ||
6 | #include "bu/list.h" | ||
7 | #include <dlfcn.h> | ||
8 | #include "bu/exceptions.h" | ||
9 | #include "bu/fstring.h" | ||
10 | |||
11 | namespace Bu | ||
12 | { | ||
13 | typedef struct PluginInfo | ||
14 | { | ||
15 | const char *sID; | ||
16 | const char *sAuthor; | ||
17 | unsigned short nVersion; | ||
18 | unsigned short nRevision; | ||
19 | void *(*createPlugin)(); | ||
20 | void (*destroyPlugin)( void * ); | ||
21 | } PluginInfo; | ||
22 | |||
23 | typedef struct PluginReg | ||
24 | { | ||
25 | bool bBuiltin; | ||
26 | void *dlHandle; | ||
27 | PluginInfo *pInfo; | ||
28 | } PluginReg; | ||
29 | |||
30 | #define PluginInterface( classname, baseclass, name, ver, rev ) \ | ||
31 | extern "C" { \ | ||
32 | baseclass *create ##classname() \ | ||
33 | { \ | ||
34 | return new classname(); \ | ||
35 | } \ | ||
36 | void destroy ##classname( baseclass *pCls ) \ | ||
37 | { \ | ||
38 | delete pCls; \ | ||
39 | } \ | ||
40 | PluginInfo classname = { \ | ||
41 | #classname, name, ver, rev, \ | ||
42 | create ##classname, destroy ##classname }; \ | ||
43 | } | ||
44 | |||
45 | #define PluginInterface2( pluginname, classname, baseclass, name, ver, rev ) \ | ||
46 | extern "C" { \ | ||
47 | baseclass *create ##classname() \ | ||
48 | { \ | ||
49 | return new classname(); \ | ||
50 | } \ | ||
51 | void destroy ##classname( baseclass *pCls ) \ | ||
52 | { \ | ||
53 | delete pCls; \ | ||
54 | } \ | ||
55 | PluginInfo pluginname = { \ | ||
56 | #pluginname, name, ver, rev, \ | ||
57 | (void *(*)())(create ##classname), \ | ||
58 | (void (*)( void * ))(destroy ##classname) }; \ | ||
59 | } | ||
60 | |||
61 | #define PluginInterface3( structname, pluginname, classname, baseclass, name, ver, rev ) \ | ||
62 | extern "C" { \ | ||
63 | baseclass *create ##classname() \ | ||
64 | { \ | ||
65 | return new classname(); \ | ||
66 | } \ | ||
67 | void destroy ##classname( baseclass *pCls ) \ | ||
68 | { \ | ||
69 | delete pCls; \ | ||
70 | } \ | ||
71 | PluginInfo structname = { \ | ||
72 | #pluginname, name, ver, rev, \ | ||
73 | (void *(*)())(create ##classname), \ | ||
74 | (void (*)( void * ))(destroy ##classname) }; \ | ||
75 | } | ||
76 | |||
77 | template<class T> | ||
78 | class Plugger | ||
79 | { | ||
80 | public: | ||
81 | typedef Bu::Hash<Bu::FString, PluginReg *> PluginHash; | ||
82 | typedef Bu::Hash<int, void *> InstHash; | ||
83 | |||
84 | public: | ||
85 | Plugger() | ||
86 | { | ||
87 | } | ||
88 | |||
89 | virtual ~Plugger() | ||
90 | { | ||
91 | for( InstHash::iterator i = hObj.begin(); i != hObj.end(); i++ ) | ||
92 | { | ||
93 | T *pPlug = (T *)i.getKey(); | ||
94 | PluginReg *pReg = (PluginReg *)*i; | ||
95 | pReg->pInfo->destroyPlugin( pPlug ); | ||
96 | } | ||
97 | |||
98 | for( PluginHash::iterator i = hPlugin.begin(); | ||
99 | i != hPlugin.end(); i++ ) | ||
100 | { | ||
101 | if( (*i)->bBuiltin == false ) | ||
102 | { | ||
103 | dlclose( (*i)->dlHandle ); | ||
104 | } | ||
105 | delete (*i); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void registerBuiltinPlugin( PluginInfo *pInfo ) | ||
110 | { | ||
111 | PluginReg *pReg = new PluginReg; | ||
112 | pReg->bBuiltin = true; | ||
113 | pReg->pInfo = pInfo; | ||
114 | hPlugin.insert( pInfo->sID, pReg ); | ||
115 | } | ||
116 | |||
117 | void registerExternalPlugin( const char *sFName, const char *sPluginName ) | ||
118 | { | ||
119 | PluginReg *pReg = (PluginReg *)hPlugin[sPluginName]; | ||
120 | if( pReg != NULL ) | ||
121 | { | ||
122 | hPlugin.erase( sPluginName ); | ||
123 | dlclose( pReg->dlHandle ); | ||
124 | delete pReg; | ||
125 | pReg = NULL; | ||
126 | } | ||
127 | |||
128 | pReg = new PluginReg; | ||
129 | |||
130 | pReg->bBuiltin = false; | ||
131 | pReg->dlHandle = dlopen( sFName, RTLD_NOW ); | ||
132 | if( pReg->dlHandle == NULL ) | ||
133 | { | ||
134 | throw PluginException( 1, "Error on %s: %s", sFName, dlerror() ); | ||
135 | } | ||
136 | pReg->pInfo = (PluginInfo *)dlsym( pReg->dlHandle, sPluginName ); | ||
137 | if( pReg->pInfo == NULL ) | ||
138 | { | ||
139 | throw PluginException( 2, "Error on %s: %s", sFName, dlerror() ); | ||
140 | } | ||
141 | hPlugin.insert( pReg->pInfo->sID, pReg ); | ||
142 | } | ||
143 | |||
144 | T *instantiate( const char *lpName ) | ||
145 | { | ||
146 | PluginReg *pReg = (PluginReg *)hPlugin[lpName]; | ||
147 | if( pReg == NULL ) | ||
148 | return NULL; | ||
149 | |||
150 | T *p = (T *)pReg->pInfo->createPlugin(); | ||
151 | hObj.insert( p, pReg ); | ||
152 | //printf("pReg: %08X, pPlug: %08X\n", pReg, p ); | ||
153 | |||
154 | return p; | ||
155 | } | ||
156 | |||
157 | bool hasPlugin( const char *lpName ) | ||
158 | { | ||
159 | if( hPlugin[lpName] == NULL ) | ||
160 | return false; | ||
161 | return true; | ||
162 | } | ||
163 | |||
164 | void destroy( T *pPlug ) | ||
165 | { | ||
166 | PluginReg *pReg = (PluginReg *)hObj[pPlug]; | ||
167 | //printf("pReg: %08X, pPlug: %08X\n", pReg, pPlug ); | ||
168 | if( pReg == NULL ) | ||
169 | return; | ||
170 | |||
171 | pReg->pInfo->destroyPlugin( pPlug ); | ||
172 | |||
173 | hObj.erase( pPlug ); | ||
174 | } | ||
175 | |||
176 | void unloadAll() | ||
177 | { | ||
178 | for( PluginHash::iterator i = hPlugin.begin(); | ||
179 | i != hPlugin.end(); i++ ) | ||
180 | { | ||
181 | if( (*i)->bBuiltin == false ) | ||
182 | { | ||
183 | dlclose( (*i)->dlHandle ); | ||
184 | } | ||
185 | delete (*i); | ||
186 | } | ||
187 | hPlugin.clear(); | ||
188 | } | ||
189 | |||
190 | private: | ||
191 | PluginHash hPlugin; | ||
192 | InstHash hObj; | ||
193 | }; | ||
194 | } | ||
195 | |||
196 | #endif | ||