2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 // seems to be required for str.h
26 #include <glib/gstdio.h>
29 #if defined ( __linux__ ) || defined ( __APPLE__ )
34 ===================================================
36 ===================================================
42 static PFN_SYN_PRINTF_VA g_pPrintf = NULL;
44 void Set_Syn_Printf( PFN_SYN_PRINTF_VA pf ){
48 #define BUFFER_SIZE 4096
50 void Syn_Printf( const char *text, ... ){
51 char buf[BUFFER_SIZE];
59 va_start( args, text );
60 ( *g_pPrintf )( text, args );
65 va_start( args, text );
66 vsnprintf( buf, BUFFER_SIZE, text, args );
67 buf[BUFFER_SIZE - 1] = 0;
76 =======================================================================
78 =======================================================================
81 // this must be kept in sync with EAPIType
82 static const char* APITypeName[4] =
90 CSynapseServer::CSynapseServer(){
97 CSynapseServer::~CSynapseServer(){
99 xmlFree( m_api_name );
104 Syn_Printf( "TODO: free API managers\n" );
107 void CSynapseServer::AddSearchPath( char* path ){
108 char *pLocalPath = new char[strlen( path ) + 1];
109 strcpy( pLocalPath, path );
110 mSearchPaths.push_front( pLocalPath );
113 bool CSynapseServer::Initialize( const char* conf_file, PFN_SYN_PRINTF_VA pf ){
114 // browse the paths to locate all potential modules
116 Set_Syn_Printf( pf );
119 // if a config file is specified and we fail to load it, we fail
120 Syn_Printf( "loading synapse XML config file '%s'\n", conf_file );
121 mpDoc = xmlParseFile( conf_file );
123 Syn_Printf( "'%s' invalid/not found\n", conf_file );
128 for ( list<char *>::iterator iPath = mSearchPaths.begin(); iPath != mSearchPaths.end(); iPath++ )
130 const char* path = *iPath;
132 Syn_Printf( "Synapse Scanning modules path: %s\n", path );
134 GDir* dir = g_dir_open( path, 0, NULL );
139 const gchar* name = g_dir_read_name( dir );
140 if ( name == NULL ) {
144 // too small to be isolated in win32/ and linux/ directories..
145 #if defined( _WIN32 )
146 const char* ext_so = ".dll";
147 #elif defined ( __linux__ ) || defined ( __APPLE__ )
148 const char* ext_so = ".so";
150 const char* ext = strrchr( name, '.' );
151 if ( ( ext == NULL ) || ( stricmp( ext, ext_so ) != 0 ) ) {
156 newModule.Format( "%s%s", path, name );
157 Syn_Printf( "Found '%s'\n", newModule.GetBuffer() );
158 EnumerateInterfaces( newModule );
167 #if defined( _WIN32 )
168 #define FORMAT_BUFSIZE 2048
169 const char* CSynapseServer::FormatGetLastError(){
170 static char buf[FORMAT_BUFSIZE];
172 FORMAT_MESSAGE_FROM_SYSTEM |
173 FORMAT_MESSAGE_IGNORE_INSERTS,
176 MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language
184 void CSynapseServer::EnumerateInterfaces( Str &soname ){
185 CSynapseClientSlot slot;
186 slot.mpDLL = LoadLibrary( soname.GetBuffer() );
188 Syn_Printf( "LoadLibrary '%s' failed\n", soname.GetBuffer() );
189 Syn_Printf( " GetLastError: %s", FormatGetLastError() );
192 slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)GetProcAddress( slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES );
193 if ( !slot.mpEnumerate ) {
194 Syn_Printf( "GetProcAddress('%s') failed\n", NAME_SYNAPSE_ENUMERATEINTERFACES );
195 Syn_Printf( " GetLastError: %s", FormatGetLastError() );
198 Syn_Printf( "Enumerate interfaces on '%s'\n", soname.GetBuffer() );
199 slot.mpClient = slot.mpEnumerate( SYNAPSE_VERSION, this );
200 if ( !slot.mpClient ) {
201 Syn_Printf( "Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer() );
202 if ( !FreeLibrary( slot.mpDLL ) ) {
203 Syn_Printf( " FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError() );
207 slot.mFileName = soname;
208 mClients.push_front( slot );
211 void CSynapseClientSlot::ReleaseSO(){
213 Syn_Printf( "ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo() );
216 Syn_Printf( "FreeLibrary '%s'\n", mpClient->GetInfo() );
217 if ( !FreeLibrary( mpDLL ) ) {
218 Syn_Printf( " FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError() );
223 #elif defined( __linux__ ) || defined ( __APPLE__ )
224 void CSynapseServer::EnumerateInterfaces( Str &soname ){
225 CSynapseClientSlot slot;
226 slot.mpDLL = dlopen( soname.GetBuffer(), RTLD_NOW );
229 if ( ( error = (char *)dlerror() ) == NULL ) {
232 Syn_Printf( "dlopen '%s' failed\n dlerror: '%s'\n", soname.GetBuffer(), error );
235 slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)dlsym( slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES );
236 if ( !slot.mpEnumerate ) {
238 if ( ( error = (char *)dlerror() ) == NULL ) {
241 Syn_Printf( "dlsym '%s' failed on shared object '%s'\n dlerror: '%s'\n", NAME_SYNAPSE_ENUMERATEINTERFACES, soname.GetBuffer(), error );
244 Syn_Printf( "Enumerate interfaces on '%s'\n", soname.GetBuffer() );
245 slot.mpClient = slot.mpEnumerate( SYNAPSE_VERSION, this );
246 if ( !slot.mpClient ) {
247 Syn_Printf( "Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer() );
248 if ( dlclose( slot.mpDLL ) ) {
250 if ( ( error = (char *)dlerror() ) == NULL ) {
253 Syn_Printf( " dlclose failed: dlerror: '%s'\n", error );
257 slot.mFileName = soname;
258 mClients.push_front( slot );
261 void CSynapseClientSlot::ReleaseSO(){
263 Syn_Printf( "ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo() );
266 Syn_Printf( "dlclose '%s'\n", mpClient->GetInfo() );
267 if ( dlclose( mpDLL ) ) {
269 if ( ( error = (char *)dlerror() ) == NULL ) {
272 Syn_Printf( " dlclose failed: dlerror: '%s'\n", error );
279 void CSynapseServer::EnumerateBuiltinModule( CSynapseBuiltinClient *pClient ){
280 CSynapseClientSlot slot;
281 pClient->EnumerateInterfaces( this );
282 slot.mpClient = pClient;
283 slot.mType = SYN_BUILTIN;
284 mClients.push_front( slot );
287 PFN_SYN_PRINTF_VA CSynapseServer::Get_Syn_Printf(){
291 void CSynapseServer::TryPushStack( APIDescriptor_t *pAPI ){
292 list<APIDescriptor_t*>::iterator iAPI;
293 for ( iAPI = mStack.begin(); iAPI != mStack.end(); iAPI++ )
295 if ( ( *iAPI ) == pAPI ) {
299 mStack.push_front( pAPI );
300 mbStackChanged = true;
303 list<CSynapseClientSlot>::iterator CSynapseServer::ShutdownClient( list<CSynapseClientSlot>::iterator iSlot ){
304 CSynapseClientSlot *pClientSlot = &( *iSlot );
305 if ( pClientSlot->mpClient->IsActive() ) {
306 // this should not happen except during core shutdown (i.e. editor is shutting down)
307 Syn_Printf( "WARNING: ShutdownClient attempted on an active module '%s'\n", pClientSlot->mpClient->GetInfo() );
311 api_count = pClientSlot->mpClient->GetAPICount();
312 for ( i = 0; i < api_count; i++ )
314 APIDescriptor_t *pAPI = pClientSlot->mpClient->GetAPIDescriptor( i );
315 // search this API in mStack
316 list< APIDescriptor_t *>::iterator iStack = mStack.begin();
317 while ( iStack != mStack.end() )
319 if ( *iStack == pAPI ) {
324 if ( iStack != mStack.end() ) {
325 if ( pAPI->mType == SYN_REQUIRE ) {
326 if ( pAPI->mbTableInitDone ) {
327 // even if non active, some SYN_REQUIRE may have been filled up
328 // look for the corresponding SYN_PROVIDE and decref
329 list< APIDescriptor_t *>::iterator iStackRequire = mStack.begin();
330 APIDescriptor_t *pMatchAPI;
331 while ( iStackRequire != mStack.end() )
333 pMatchAPI = *iStackRequire;
334 if ( pMatchAPI->mType == SYN_PROVIDE && MatchAPI( pMatchAPI, pAPI ) ) {
339 if ( iStackRequire != mStack.end() ) {
340 // we have found the corresponding SYN_PROVIDE
341 pMatchAPI->mRefCount--;
345 // this is not supposed to happen at all
346 Syn_Printf( "ERROR: couldn't find the SYN_PROVIDE for an initialized SYN_REQUIRE API '%s' '%s' '%s'\n", pAPI->major_name, pAPI->minor_name, pClientSlot->mpClient->GetInfo() );
350 else if ( pAPI->mType == SYN_PROVIDE ) {
351 // this should never happen on non active clients, it may happen during a core shutdown though
352 // if the mRefCount is != 0, that means there is at least a function table out there that will segfault things
353 Syn_Printf( "WARNING: found a SYN_PROVIDE API '%s' '%s' with refcount %d in CSynapseServer::ShutdownClient for '%s'\n", pAPI->major_name, pAPI->minor_name, pAPI->mRefCount, pClientSlot->mpClient->GetInfo() );
355 // mostly safe to remove it now
356 mStack.erase( iStack );
359 // we can actually release the module now
360 // NOTE: do we want to have a 'final shutdown' call to the client? (not as long as we don't have a use for it)
361 if ( pClientSlot->mType == SYN_SO ) {
362 pClientSlot->ReleaseSO();
364 return mClients.erase( iSlot );
367 void CSynapseServer::PushRequired( CSynapseClient *pClient ){
368 /* walk through the standard APIs and push them in */
369 int i,max = pClient->GetAPICount();
370 for ( i = 0; i < max; i++ )
372 APIDescriptor_t* pAPI = pClient->GetAPIDescriptor( i );
373 if ( pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone ) {
374 TryPushStack( pAPI );
378 /* if this client has 'List' API Manager types, walk through them for addition too */
379 max = pClient->GetManagerListCount();
380 for ( i = 0; i < max; i++ )
382 CSynapseAPIManager *pManager = pClient->GetManagerList( i );
383 assert( pManager->GetType() == API_LIST );
384 pManager->InitializeAPIList();
386 for ( j = 0; j < pManager->GetAPICount(); j++ )
388 TryPushStack( pManager->GetAPI( j ) );
392 /* if there are loose match managers, prompt them against the current list of SYN_PROVIDE interfaces
393 * and let them decide which ones they might want
396 max = pClient->GetManagerMatchCount();
398 for ( i = 0; i < max; i++ )
400 CSynapseAPIManager *pManager = pClient->GetManagerMatch( i );
401 // start matching all known SYN_PROVIDE APIs against this manager
402 list<CSynapseClientSlot>::iterator iClientSlot;
403 for ( iClientSlot = mClients.begin(); iClientSlot != mClients.end(); iClientSlot++ )
405 CSynapseClient *pScanClient = ( *iClientSlot ).
407 int j,jmax = pScanClient->GetAPICount();
408 for ( j = 0; j < jmax; j++ )
410 APIDescriptor_t *pAPI = pScanClient->GetAPIDescriptor( j );
411 if ( pAPI->mType == SYN_PROVIDE ) {
412 if ( pManager->MatchAPI( pAPI->major_name, pAPI->minor_name ) ) {
413 /*! we are going to want to load this one
414 * NOTE TTimo: what if this can not be resolved in the end?
415 * if this happens, then the whole startup will fail instead
416 * or we can use SYN_REQUIRE_ANY and drop it without consequences
418 APIDescriptor_t *pPushAPI = pManager->BuildRequireAPI( pAPI );
419 TryPushStack( pPushAPI );
427 bool CSynapseServer::MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ){
428 return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name );
431 bool CSynapseServer::MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ){
432 if ( strcmp( major1, major2 ) ) {
435 // either no minor at all for this API, or matching
436 if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) {
439 // or one of the minors says "*" (knowing that the majors match already)
440 if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) {
446 bool CSynapseServer::ResolveAPI( APIDescriptor_t* pAPI ){
447 //Syn_Printf("In ResolveAPI %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name);
448 // loop through active clients, search for a client providing what we are looking for
449 list<CSynapseClientSlot>::iterator iClient;
450 for ( iClient = mClients.begin(); iClient != mClients.end(); iClient++ )
452 // walk through interfaces on this client for a match
453 CSynapseClient *pScanClient = ( *iClient ).mpClient;
454 int i,max = pScanClient->GetAPICount();
455 for ( i = 0; i < max; i++ )
457 APIDescriptor_t *pScanClientAPI = pScanClient->GetAPIDescriptor( i );
458 if ( pScanClientAPI->mType == SYN_PROVIDE ) {
459 if ( MatchAPI( pAPI, pScanClientAPI ) ) {
460 // can this client provide APIs yet
461 // it is possible that all of it's APIs have been filled and it's not been activated yet
462 pScanClient->CheckSetActive();
463 if ( pScanClient->IsActive() ) {
464 // make sure this interface has correct size (this is our version check)
465 if ( pAPI->mSize != pScanClientAPI->mSize ) {
466 Syn_Printf( "ERROR: version mismatch for API '%s' '%s' found in '%s' (size %d != %d)\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI->mSize, pScanClientAPI->mSize );
467 Syn_Printf( " the module and the server are incompatible\n" );
468 // keep going to other APIs
471 // this is an active client, we can request
472 #ifdef SYNAPSE_VERBOSE
473 Syn_Printf( "RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI );
475 if ( !pScanClient->RequestAPI( pAPI ) ) {
476 // this should never happen, means we think this module provides the API, but it answers that it doesn't
477 Syn_Printf( "ERROR: RequestAPI failed\n" );
480 pScanClientAPI->mRefCount++;
481 pAPI->mbTableInitDone = true;
482 return true; // job done
486 // this client is not active yet, some of it's required interfaces are not filled in
487 PushRequired( pScanClient );
488 // we will exit the scan through the APIDescriptor of this client and look at other clients
498 bool CSynapseServer::DoResolve( CSynapseClient *pClient ){
499 list<CSynapseClientSlot>::iterator iSlot;
500 for ( iSlot = mClients.begin(); iSlot != mClients.end(); iSlot++ )
502 if ( ( *iSlot ).mpClient == pClient ) {
506 if ( iSlot == mClients.end() ) {
507 Syn_Printf( "CSynapserServer::Resolve adding new client slot '%s'\n", pClient->GetInfo() );
508 CSynapseClientSlot slot;
509 slot.mpClient = pClient;
510 slot.mFileName = "local client";
511 // make it active so we can request the interfaces already
512 pClient->ForceSetActive();
513 mClients.push_front( slot );
517 // make it active so we can request the interfaces already
518 ( *iSlot ).mpClient->ForceSetActive();
521 // push the interfaces that need to be resolved for this client
522 // NOTE: this doesn't take care of the SYN_REQUIRE_ANY interfaces
523 PushRequired( pClient );
524 // start resolving now
525 // working till the stack is emptied or till we reach a dead end situation
526 // we do a depth first traversal, we will grow the interface stack to be resolved till we start finding solutions
527 list<APIDescriptor_t*>::iterator iCurrent;
528 mbStackChanged = true; // init to true so we try the first elem
529 while ( !mStack.empty() )
532 if ( !mbStackChanged ) {
533 // the stack didn't change last loop
535 if ( iCurrent == mStack.end() ) {
536 Syn_Printf( "ERROR: CSynapseServer::Resolve, failed to resolve\n" );
540 if ( ResolveAPI( *iCurrent ) ) {
541 iCurrent = mStack.erase( iCurrent );
542 mbStackChanged = true;
547 // the stack changed at last loop
548 mbStackChanged = false;
549 iCurrent = mStack.begin();
550 if ( ResolveAPI( *iCurrent ) ) {
551 iCurrent = mStack.erase( iCurrent );
552 mbStackChanged = true;
559 bool CSynapseServer::Resolve( CSynapseClient *pClient ){
560 bool ret = DoResolve( pClient );
561 list<CSynapseClientSlot>::iterator iClient;
562 iClient = mClients.begin();
563 while ( iClient != mClients.end() )
565 CSynapseClient *pClient = ( *iClient ).mpClient;
566 if ( !pClient->IsActive() ) {
567 Syn_Printf( "Unloading an unused module: '%s'\n", pClient->GetInfo() );
568 iClient = ShutdownClient( iClient );
577 void CSynapseServer::Shutdown(){
578 Syn_Printf( "Synapse server core is shutting down\n" );
579 // do a first pass to shutdown the clients nicely (i.e. decref, release memory and drop everything)
580 // we seperate the client shutdown calls from the dlclose cause that part is a clean decref / free situation whereas dlclose will break links without advice
581 list<CSynapseClientSlot>::iterator iClient;
582 iClient = mClients.begin();
583 for ( iClient = mClients.begin(); iClient != mClients.end(); iClient++ )
585 ( *iClient ).mpClient->Shutdown();
587 // now release them from the server's point of view
588 iClient = mClients.begin();
589 while ( iClient != mClients.end() )
591 iClient = ShutdownClient( iClient );
595 void CSynapseServer::DumpStack(){
596 list<APIDescriptor_t*>::iterator iCurrent;
597 for ( iCurrent = mStack.begin(); iCurrent != mStack.end(); iCurrent++ )
599 APIDescriptor_t*pAPI = *iCurrent;
600 Syn_Printf( "interface %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name );
604 void CSynapseServer::DumpActiveClients(){
605 list<CSynapseClientSlot>::iterator iClient;
606 for ( iClient = mClients.begin(); iClient != mClients.end(); iClient++ )
608 CSynapseClient *pClient = ( *iClient ).mpClient;
609 Syn_Printf( "%s", pClient->GetInfo() );
610 if ( pClient->IsActive() ) {
614 Syn_Printf( " (not active)\n" );
619 bool CSynapseServer::SelectClientConfig( const char *client_name ){
623 xmlNodePtr pNode = xmlDocGetRootElement( mpDoc );
627 // look for the client
628 pNode = pNode->children;
631 if ( pNode->type == XML_ELEMENT_NODE ) {
632 xmlChar *prop = xmlGetProp( pNode, (const xmlChar *)"name" );
633 if ( !strcmp( (const char *)prop, client_name ) ) {
642 return false; // config you asked for isn't there
645 mpFocusedNode = pNode->children;
646 mpCurrentClientConfig = pNode;
650 bool CSynapseServer::GetNextConfig( char **api_name, char **minor ){
651 while ( mpFocusedNode && mpFocusedNode->name )
653 if ( mpFocusedNode->type == XML_ELEMENT_NODE && !strcmp( (const char *)mpFocusedNode->name, "api" ) ) {
655 xmlFree( m_api_name );
657 m_api_name = xmlGetProp( mpFocusedNode, (const xmlChar *)"name" );
658 *api_name = (char *)m_api_name;
662 m_content = g_strdup( (const gchar *)mpFocusedNode->children->content );
663 g_strstrip( m_content );
665 mpFocusedNode = mpFocusedNode->next;
668 mpFocusedNode = mpFocusedNode->next;
673 bool CSynapseServer::GetConfigForAPI( const char *api, char **minor ) {
674 xmlNodePtr pNode = mpCurrentClientConfig->children;
675 while ( pNode && pNode->name ) {
676 if ( pNode->type == XML_ELEMENT_NODE && !strcmp( (const char *)pNode->name, "api" ) ) {
678 xmlFree( m_api_name );
680 m_api_name = xmlGetProp( pNode, (const xmlChar *)"name" );
681 if ( !strcmp( (const char *)m_api_name, api ) ) {
685 m_content = g_strdup( (const gchar *)pNode->children->content );
686 g_strstrip( m_content );
696 const char *CSynapseServer::GetModuleFilename( CSynapseClient *pClient ){
697 list<CSynapseClientSlot>::iterator iSlot;
698 for ( iSlot = mClients.begin(); iSlot != mClients.end(); iSlot++ )
700 if ( ( *iSlot ).mpClient == pClient ) {
701 if ( ( *iSlot ).mType == SYN_BUILTIN ) {
706 return ( *iSlot ).mFileName;
714 =======================================================================
716 =======================================================================
719 CSynapseClient::CSynapseClient(){
722 void CSynapseClient::Shutdown(){
723 vector<APIDescriptor_t *>::iterator iAPI;
724 for ( iAPI = mAPIDescriptors.begin(); iAPI != mAPIDescriptors.end(); iAPI++ )
726 APIDescriptor_t *pAPI = *iAPI;
727 if ( pAPI->mRefCount != 0 ) {
728 Syn_Printf( "WARNING: ~CSynapseClient '%s' has non-zero ref count for interface '%s' '%s'\n", GetInfo(), pAPI->major_name, pAPI->minor_name );
735 mAPIDescriptors.clear();
736 vector<CSynapseAPIManager *>::iterator iManager;
737 for ( iManager = mManagersList.begin(); iManager != mManagersList.end(); iManager++ )
739 CSynapseAPIManager *pManager = *iManager;
743 mManagersList.clear();
744 for ( iManager = mManagersMatch.begin(); iManager != mManagersMatch.end(); iManager++ )
746 CSynapseAPIManager *pManager = *iManager;
750 mManagersMatch.clear();
753 CSynapseClient::~CSynapseClient(){
754 // this should not be doing anything when called from here if everything went right
755 // otherwise it's likely to crash .. at least that's the sign we missed something
759 int CSynapseClient::GetAPICount(){
760 return mAPIDescriptors.size();
763 APIDescriptor_t* CSynapseClient::GetAPIDescriptor( int i ){
764 return mAPIDescriptors[i];
767 int CSynapseClient::GetManagerMatchCount(){
768 return mManagersMatch.size();
771 CSynapseAPIManager* CSynapseClient::GetManagerMatch( int i ){
772 return mManagersMatch[i];
775 int CSynapseClient::GetManagerListCount(){
776 return mManagersList.size();
779 CSynapseAPIManager* CSynapseClient::GetManagerList( int i ){
780 return mManagersList[i];
783 bool CSynapseClient::AddAPI( const char *major, const char *minor, int size, EAPIType type, void *pTable ){
784 // do some safe checks before actual addition
785 if ( type == SYN_REQUIRE && !pTable ) {
786 Syn_Printf( "ERROR: interface '%s' '%s' from '%s' is SYN_REQUIRE and doesn't provide a function table pointer\n", major, minor, GetInfo() );
790 int *pi = (int *)pTable;
792 Syn_Printf( "ERROR: forgot to init function table size for interface '%s' '%s' from '%s'?\n", major, minor, GetInfo() );
796 APIDescriptor_t *pAPI = new APIDescriptor_t;
797 memset( pAPI, 0, sizeof( APIDescriptor_t ) );
798 strncpy( pAPI->major_name, major, MAX_APINAME );
800 strncpy( pAPI->minor_name, minor, MAX_APINAME );
803 pAPI->mpTable = pTable;
804 // store the interface size
805 if ( type == SYN_PROVIDE ) {
807 Syn_Printf( "ERROR: size of the interface required for a SYN_PROVIDE ('%s' '%s' from '%s')\n", major, minor, GetInfo() );
813 else if ( type == SYN_REQUIRE ) {
815 // if a non-zero value is given in function call, use this instead of the val in table
816 *( (int *)pAPI->mpTable ) = size;
821 pAPI->mSize = *( (int *)pAPI->mpTable );
822 if ( pAPI->mSize == 0 ) {
823 Syn_Printf( "ERROR: didn't get an interface size ('%s' '%s' from '%s')\n", major, minor, GetInfo() );
831 Syn_Printf( "ERROR: AddAPI type '%d' not supported\n", type );
834 mAPIDescriptors.push_back( pAPI );
835 #ifdef SYNAPSE_VERBOSE
836 Syn_Printf( "AddAPI: %s %p '%s' '%s' from '%s', size %d\n", APITypeName[pAPI->mType], pAPI, major, minor, GetInfo(), pAPI->mSize );
843 const char* CSynapseClient::GetInfo(){
844 return "CSynapseClient built " __DATE__ " " RADIANT_VERSION;
847 bool CSynapseClient::CheckSetActive(){
851 int i,max = GetAPICount();
852 for ( i = 0; i < max; i++ )
854 APIDescriptor_t *pAPI = GetAPIDescriptor( i );
855 if ( pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone ) {
859 // if we have managers with fixed list, those need to be completely filled in too
860 vector<CSynapseAPIManager *>::iterator iManager;
861 for ( iManager = mManagersList.begin(); iManager != mManagersList.end(); iManager++ )
863 if ( !( *iManager )->CheckSetActive() ) {
864 return false; // one of the managers doesn't have all it needs yet
867 // call OnActivate to let the client perform last minute checks
868 // NOTE: this should be fatal instead of letting the engine try other combinations
869 if ( !OnActivate() ) {
872 // yes, all required interfaces have been initialized
873 Syn_Printf( "'%s' activated\n", GetInfo() );
878 bool CSynapseClient::ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ) {
880 if ( !client_name ) {
881 client_name = GetName();
884 Syn_Printf( "Dynamic APIs for client '%s'\n", GetInfo() );
885 if ( !pServer->SelectClientConfig( client_name ) ) {
886 Syn_Printf( "Failed to select synapse client config '%s'\n", client_name );
891 while ( entries[i].type != SYN_UNKNOWN ) { // don't test pTable, for a SYN_PROVIDE it will be empty
893 if ( !pServer->GetConfigForAPI( entries[i].api, &minor ) ) {
894 Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", entries[i].api );
897 AddAPI( entries[i].api, minor, entries[i].size, entries[i].type, entries[i].pTable );
900 Syn_Printf( "%d dynamic interfaces parsed for '%s'\n", i, client_name );
904 void CSynapseClient::AddManager( CSynapseAPIManager *pManager ){
906 if ( pManager->GetType() == API_LIST ) {
907 mManagersList.push_back( pManager );
910 mManagersMatch.push_back( pManager );
914 CSynapseAPIManager::~CSynapseAPIManager(){
915 vector<APIDescriptor_t *>::iterator iAPI;
916 for ( iAPI = mAPIs.begin(); iAPI != mAPIs.end(); iAPI++ )
918 APIDescriptor_t *pAPI = *iAPI;
919 if ( pAPI->mRefCount != 0 ) {
920 Syn_Printf( "WARNING: ~CSynapseAPIManager has non-zero ref count for interface '%s' '%s'\n", pAPI->major_name, pAPI->minor_name );
927 APIDescriptor_t* CSynapseAPIManager::PrepareRequireAPI( APIDescriptor_t *pAPI ){
929 if ( pAPI->mType != SYN_PROVIDE ) {
930 Syn_Printf( "ERROR: unexpected pAPI->mType != SYN_PROVIDE in CSynapseAPIManager::PrepareRequireAPI\n" );
934 APIDescriptor_t *pRequireAPI = new APIDescriptor_t;
935 memcpy( pRequireAPI, pAPI, sizeof( APIDescriptor_t ) );
936 pRequireAPI->mType = SYN_REQUIRE_ANY;
937 pRequireAPI->mpTable = NULL;
938 pRequireAPI->mbTableInitDone = false;
939 pRequireAPI->mSize = 0; // this will have to be set correctly by the child for version checking
940 pRequireAPI->mRefCount = 0;
944 void CSynapseAPIManager::SetMatchAPI( const char *major, const char *minor ){
945 if ( strlen( minor ) > MAX_PATTERN_STRING ) {
946 Syn_Printf( "ERROR: MAX_TOKEN_STRING exceeded in CSynapseAPIManager::SetMatchAPI: '%s'\n", minor );
949 strcpy( major_pattern, major );
950 strcpy( minor_pattern, minor );
951 if ( strcmp( minor, "*" ) ) {
956 bool CSynapseAPIManager::MatchAPI( const char *major, const char *minor ){
957 assert( mType == API_MATCH );
960 if this interface has been allocated already, avoid requesting it again..
962 vector<APIDescriptor_t *>::iterator iAPI;
963 for ( iAPI = mAPIs.begin(); iAPI != mAPIs.end(); iAPI++ )
965 if ( CSynapseServer::MatchAPI( ( *iAPI )->major_name, ( *iAPI )->minor_name, major, minor ) ) {
970 if ( !strcmp( major, major_pattern ) ) {
976 bool CSynapseAPIManager::CheckSetActive(){
977 if ( mType == API_MATCH ) {
981 int i,max = GetAPICount();
982 for ( i = 0; i < max; i++ )
984 if ( !GetAPI( i )->mbTableInitDone ) {
991 void CSynapseAPIManager::InitializeAPIList(){
992 char minor_tok[MAX_PATTERN_STRING];
995 if ( mAPIs.size() ) {
996 Syn_Printf( "WARNING: CSynapseAPIManager::InitializeAPIList on an already initialized APIManager\n" );
1000 strncpy( minor_tok, minor_pattern, MAX_PATTERN_STRING );
1001 token = strtok( minor_tok, " " );
1004 /* ask the child to build from scratch */
1005 APIDescriptor_t *pAPI = new APIDescriptor_t;
1006 memset( pAPI, 0, sizeof( APIDescriptor_t ) );
1007 strncpy( pAPI->major_name, major_pattern, MAX_APINAME );
1008 strncpy( pAPI->minor_name, token, MAX_APINAME );
1009 pAPI->mType = SYN_REQUIRE_ANY;
1010 FillAPITable( pAPI );
1011 mAPIs.push_back( pAPI );
1012 token = strtok( NULL, " " );
1016 int CSynapseAPIManager::GetAPICount(){
1017 return mAPIs.size();
1020 APIDescriptor_t* CSynapseAPIManager::GetAPI( int i ){