2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
24 // seems to be required for str.h
\r
26 #include <glib/gstdio.h>
\r
28 #include "synapse.h"
\r
29 #if defined (__linux__) || defined (__APPLE__)
\r
34 ===================================================
\r
36 ===================================================
\r
42 static PFN_SYN_PRINTF_VA g_pPrintf = NULL;
\r
44 void Set_Syn_Printf(PFN_SYN_PRINTF_VA pf)
\r
49 #define BUFFER_SIZE 4096
\r
51 void Syn_Printf (const char *text, ...)
\r
53 char buf[BUFFER_SIZE];
\r
61 va_start (args, text);
\r
62 (*g_pPrintf)(text, args);
\r
67 va_start (args, text);
\r
68 vsnprintf (buf, BUFFER_SIZE, text, args);
\r
69 buf[BUFFER_SIZE-1] = 0;
\r
78 =======================================================================
\r
80 =======================================================================
\r
83 // this must be kept in sync with EAPIType
\r
84 static const char* APITypeName[4] =
\r
92 CSynapseServer::CSynapseServer()
\r
97 mpFocusedNode = NULL;
\r
100 CSynapseServer::~CSynapseServer()
\r
103 xmlFree(m_api_name);
\r
106 Syn_Printf("TODO: free API managers\n");
\r
109 void CSynapseServer::AddSearchPath(char* path)
\r
111 char *pLocalPath = new char[strlen(path)+1];
\r
112 strcpy(pLocalPath, path);
\r
113 mSearchPaths.push_front(pLocalPath);
\r
116 bool CSynapseServer::Initialize(const char* conf_file, PFN_SYN_PRINTF_VA pf)
\r
118 // browse the paths to locate all potential modules
\r
120 Set_Syn_Printf(pf);
\r
124 // if a config file is specified and we fail to load it, we fail
\r
125 Syn_Printf("loading synapse XML config file '%s'\n", conf_file);
\r
126 mpDoc = xmlParseFile(conf_file);
\r
129 Syn_Printf("'%s' invalid/not found\n", conf_file);
\r
134 for (list<char *>::iterator iPath=mSearchPaths.begin(); iPath!=mSearchPaths.end(); iPath++)
\r
136 const char* path = *iPath;
\r
138 Syn_Printf("Synapse Scanning modules path: %s\n", path);
\r
140 GDir* dir = g_dir_open (path, 0, NULL);
\r
146 const gchar* name = g_dir_read_name(dir);
\r
150 // too small to be isolated in win32/ and linux/ directories..
\r
151 #if defined(_WIN32)
\r
152 const char* ext_so = ".dll";
\r
153 #elif defined (__linux__) || defined (__APPLE__)
\r
154 const char* ext_so = ".so";
\r
156 const char* ext = strrchr (name, '.');
\r
157 if ((ext == NULL) || (stricmp (ext, ext_so) != 0))
\r
161 newModule.Format("%s%s", path, name);
\r
162 Syn_Printf("Found '%s'\n", newModule.GetBuffer());
\r
163 EnumerateInterfaces(newModule);
\r
172 #if defined(_WIN32)
\r
173 #define FORMAT_BUFSIZE 2048
\r
174 const char* CSynapseServer::FormatGetLastError()
\r
176 static char buf[FORMAT_BUFSIZE];
\r
178 FORMAT_MESSAGE_FROM_SYSTEM |
\r
179 FORMAT_MESSAGE_IGNORE_INSERTS,
\r
182 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
\r
190 void CSynapseServer::EnumerateInterfaces(Str &soname)
\r
192 CSynapseClientSlot slot;
\r
193 slot.mpDLL = LoadLibrary(soname.GetBuffer());
\r
196 Syn_Printf("LoadLibrary '%s' failed\n", soname.GetBuffer());
\r
197 Syn_Printf(" GetLastError: %s", FormatGetLastError());
\r
200 slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)GetProcAddress(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES);
\r
201 if (!slot.mpEnumerate)
\r
203 Syn_Printf("GetProcAddress('%s') failed\n", NAME_SYNAPSE_ENUMERATEINTERFACES);
\r
204 Syn_Printf(" GetLastError: %s", FormatGetLastError());
\r
207 Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer());
\r
208 slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this);
\r
209 if (!slot.mpClient)
\r
211 Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer());
\r
212 if (!FreeLibrary(slot.mpDLL))
\r
214 Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError());
\r
218 slot.mFileName = soname;
\r
219 mClients.push_front(slot);
\r
222 void CSynapseClientSlot::ReleaseSO()
\r
226 Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo());
\r
229 Syn_Printf("FreeLibrary '%s'\n", mpClient->GetInfo());
\r
230 if (!FreeLibrary(mpDLL))
\r
232 Syn_Printf(" FreeLibrary failed: GetLastError: '%s'\n", CSynapseServer::FormatGetLastError());
\r
237 #elif defined(__linux__) || defined (__APPLE__)
\r
238 void CSynapseServer::EnumerateInterfaces(Str &soname)
\r
240 CSynapseClientSlot slot;
\r
241 slot.mpDLL = dlopen (soname.GetBuffer(), RTLD_NOW);
\r
242 PFN_SYNAPSE_ENUMERATEINTERFACES *pEnumerate;
\r
246 if ((error = (char *)dlerror()) == NULL)
\r
248 Syn_Printf("dlopen '%s' failed\n dlerror: '%s'\n", soname.GetBuffer(), error);
\r
251 slot.mpEnumerate = (PFN_SYNAPSE_ENUMERATEINTERFACES)dlsym(slot.mpDLL, NAME_SYNAPSE_ENUMERATEINTERFACES);
\r
252 if (!slot.mpEnumerate)
\r
255 if ((error = (char *)dlerror()) == NULL)
\r
257 Syn_Printf("dlsym '%s' failed on shared object '%s'\n dlerror: '%s'\n", NAME_SYNAPSE_ENUMERATEINTERFACES, soname.GetBuffer(), error);
\r
260 Syn_Printf("Enumerate interfaces on '%s'\n", soname.GetBuffer());
\r
261 slot.mpClient = slot.mpEnumerate(SYNAPSE_VERSION, this);
\r
262 if (!slot.mpClient)
\r
264 Syn_Printf("Enumerate interfaces on '%s' returned NULL, unloading.\n", soname.GetBuffer());
\r
265 if (dlclose(slot.mpDLL))
\r
268 if ((error = (char *)dlerror()) == NULL)
\r
270 Syn_Printf(" dlclose failed: dlerror: '%s'\n", error);
\r
274 slot.mFileName = soname;
\r
275 mClients.push_front(slot);
\r
278 void CSynapseClientSlot::ReleaseSO()
\r
282 Syn_Printf("ERROR: no shared object handle for client '%s' in CSynapseClientSlot::ReleaseSO\n", mpClient->GetInfo());
\r
285 Syn_Printf("dlclose '%s'\n", mpClient->GetInfo());
\r
286 if (dlclose(mpDLL))
\r
289 if ((error = (char *)dlerror()) == NULL)
\r
291 Syn_Printf(" dlclose failed: dlerror: '%s'\n", error);
\r
298 void CSynapseServer::EnumerateBuiltinModule(CSynapseBuiltinClient *pClient)
\r
300 CSynapseClientSlot slot;
\r
301 pClient->EnumerateInterfaces(this);
\r
302 slot.mpClient = pClient;
\r
303 slot.mType = SYN_BUILTIN;
\r
304 mClients.push_front(slot);
\r
307 PFN_SYN_PRINTF_VA CSynapseServer::Get_Syn_Printf()
\r
312 void CSynapseServer::TryPushStack(APIDescriptor_t *pAPI)
\r
314 list<APIDescriptor_t*>::iterator iAPI;
\r
315 for(iAPI=mStack.begin(); iAPI!=mStack.end(); iAPI++)
\r
317 if ((*iAPI) == pAPI)
\r
322 mStack.push_front(pAPI);
\r
323 mbStackChanged = true;
\r
326 list<CSynapseClientSlot>::iterator CSynapseServer::ShutdownClient(list<CSynapseClientSlot>::iterator iSlot)
\r
328 CSynapseClientSlot *pClientSlot = &(*iSlot);
\r
329 if (pClientSlot->mpClient->IsActive())
\r
331 // this should not happen except during core shutdown (i.e. editor is shutting down)
\r
332 Syn_Printf("WARNING: ShutdownClient attempted on an active module '%s'\n", pClientSlot->mpClient->GetInfo());
\r
336 api_count = pClientSlot->mpClient->GetAPICount();
\r
337 for(i=0; i<api_count; i++)
\r
339 APIDescriptor_t *pAPI = pClientSlot->mpClient->GetAPIDescriptor(i);
\r
340 // search this API in mStack
\r
341 list< APIDescriptor_t *>::iterator iStack = mStack.begin();
\r
342 while(iStack != mStack.end())
\r
344 if (*iStack == pAPI)
\r
348 if (iStack != mStack.end())
\r
350 if (pAPI->mType == SYN_REQUIRE)
\r
352 if (pAPI->mbTableInitDone)
\r
354 // even if non active, some SYN_REQUIRE may have been filled up
\r
355 // look for the corresponding SYN_PROVIDE and decref
\r
356 list< APIDescriptor_t *>::iterator iStackRequire = mStack.begin();
\r
357 APIDescriptor_t *pMatchAPI;
\r
358 while (iStackRequire != mStack.end())
\r
360 pMatchAPI = *iStackRequire;
\r
361 if ( pMatchAPI->mType == SYN_PROVIDE && MatchAPI( pMatchAPI, pAPI ) )
\r
365 if (iStackRequire != mStack.end())
\r
367 // we have found the corresponding SYN_PROVIDE
\r
368 pMatchAPI->mRefCount--;
\r
372 // this is not supposed to happen at all
\r
373 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());
\r
377 else if (pAPI->mType == SYN_PROVIDE)
\r
379 // this should never happen on non active clients, it may happen during a core shutdown though
\r
380 // if the mRefCount is != 0, that means there is at least a function table out there that will segfault things
\r
381 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());
\r
383 // mostly safe to remove it now
\r
384 mStack.erase(iStack);
\r
387 // we can actually release the module now
\r
388 // 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)
\r
389 if (pClientSlot->mType == SYN_SO)
\r
391 pClientSlot->ReleaseSO();
\r
393 return mClients.erase(iSlot);
\r
396 void CSynapseServer::PushRequired(CSynapseClient *pClient)
\r
398 /* walk through the standard APIs and push them in */
\r
399 int i,max = pClient->GetAPICount();
\r
400 for(i=0; i<max; i++)
\r
402 APIDescriptor_t* pAPI = pClient->GetAPIDescriptor(i);
\r
403 if (pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone)
\r
405 TryPushStack(pAPI);
\r
409 /* if this client has 'List' API Manager types, walk through them for addition too */
\r
410 max = pClient->GetManagerListCount();
\r
411 for(i=0; i<max; i++)
\r
413 CSynapseAPIManager *pManager = pClient->GetManagerList(i);
\r
414 assert(pManager->GetType() == API_LIST);
\r
415 pManager->InitializeAPIList();
\r
417 for(j=0; j<pManager->GetAPICount(); j++)
\r
419 TryPushStack(pManager->GetAPI(j));
\r
423 /* if there are loose match managers, prompt them against the current list of SYN_PROVIDE interfaces
\r
424 * and let them decide which ones they might want
\r
427 max = pClient->GetManagerMatchCount();
\r
429 for(i=0; i<max; i++)
\r
431 CSynapseAPIManager *pManager = pClient->GetManagerMatch(i);
\r
432 // start matching all known SYN_PROVIDE APIs against this manager
\r
433 list<CSynapseClientSlot>::iterator iClientSlot;
\r
434 for(iClientSlot=mClients.begin(); iClientSlot!=mClients.end(); iClientSlot++)
\r
436 CSynapseClient *pScanClient = (*iClientSlot).
\r
438 int j,jmax = pScanClient->GetAPICount();
\r
439 for(j=0; j<jmax; j++)
\r
441 APIDescriptor_t *pAPI = pScanClient->GetAPIDescriptor(j);
\r
442 if (pAPI->mType == SYN_PROVIDE)
\r
444 if (pManager->MatchAPI(pAPI->major_name, pAPI->minor_name))
\r
446 /*! we are going to want to load this one
\r
447 * NOTE TTimo: what if this can not be resolved in the end?
\r
448 * if this happens, then the whole startup will fail instead
\r
449 * or we can use SYN_REQUIRE_ANY and drop it without consequences
\r
451 APIDescriptor_t *pPushAPI = pManager->BuildRequireAPI(pAPI);
\r
452 TryPushStack(pPushAPI);
\r
460 bool CSynapseServer::MatchAPI(APIDescriptor_t *p1, APIDescriptor_t *p2)
\r
462 return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name );
\r
465 bool CSynapseServer::MatchAPI(const char* major1, const char* minor1, const char* major2, const char* minor2)
\r
467 if ( strcmp( major1, major2 ) ) {
\r
470 // either no minor at all for this API, or matching
\r
471 if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) {
\r
474 // or one of the minors says "*" (knowing that the majors match already)
\r
475 if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) {
\r
481 bool CSynapseServer::ResolveAPI(APIDescriptor_t* pAPI)
\r
483 //Syn_Printf("In ResolveAPI %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name);
\r
484 // loop through active clients, search for a client providing what we are looking for
\r
485 list<CSynapseClientSlot>::iterator iClient;
\r
486 for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++)
\r
488 // walk through interfaces on this client for a match
\r
489 CSynapseClient *pScanClient = (*iClient).mpClient;
\r
490 int i,max = pScanClient->GetAPICount();
\r
491 for(i=0; i<max; i++)
\r
493 APIDescriptor_t *pScanClientAPI = pScanClient->GetAPIDescriptor(i);
\r
494 if (pScanClientAPI->mType == SYN_PROVIDE)
\r
496 if (MatchAPI(pAPI, pScanClientAPI))
\r
498 // can this client provide APIs yet
\r
499 // it is possible that all of it's APIs have been filled and it's not been activated yet
\r
500 pScanClient->CheckSetActive();
\r
501 if (pScanClient->IsActive())
\r
503 // make sure this interface has correct size (this is our version check)
\r
504 if (pAPI->mSize != pScanClientAPI->mSize)
\r
506 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);
\r
507 Syn_Printf(" the module and the server are incompatible\n");
\r
508 // keep going to other APIs
\r
511 // this is an active client, we can request
\r
512 #ifdef SYNAPSE_VERBOSE
\r
513 Syn_Printf("RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI);
\r
515 if (!pScanClient->RequestAPI(pAPI))
\r
517 // this should never happen, means we think this module provides the API, but it answers that it doesn't
\r
518 Syn_Printf("ERROR: RequestAPI failed\n");
\r
521 pScanClientAPI->mRefCount++;
\r
522 pAPI->mbTableInitDone = true;
\r
523 return true; // job done
\r
527 // this client is not active yet, some of it's required interfaces are not filled in
\r
528 PushRequired(pScanClient);
\r
529 // we will exit the scan through the APIDescriptor of this client and look at other clients
\r
539 bool CSynapseServer::DoResolve(CSynapseClient *pClient)
\r
541 list<CSynapseClientSlot>::iterator iSlot;
\r
542 for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++)
\r
544 if ((*iSlot).mpClient == pClient)
\r
547 if (iSlot == mClients.end())
\r
549 Syn_Printf("CSynapserServer::Resolve adding new client slot '%s'\n", pClient->GetInfo());
\r
550 CSynapseClientSlot slot;
\r
551 slot.mpClient = pClient;
\r
552 slot.mFileName = "local client";
\r
553 // make it active so we can request the interfaces already
\r
554 pClient->ForceSetActive();
\r
555 mClients.push_front(slot);
\r
559 // make it active so we can request the interfaces already
\r
560 (*iSlot).mpClient->ForceSetActive();
\r
563 // push the interfaces that need to be resolved for this client
\r
564 // NOTE: this doesn't take care of the SYN_REQUIRE_ANY interfaces
\r
565 PushRequired(pClient);
\r
566 // start resolving now
\r
567 // working till the stack is emptied or till we reach a dead end situation
\r
568 // we do a depth first traversal, we will grow the interface stack to be resolved till we start finding solutions
\r
569 list<APIDescriptor_t*>::iterator iCurrent;
\r
570 mbStackChanged = true; // init to true so we try the first elem
\r
571 while (!mStack.empty())
\r
574 if (!mbStackChanged)
\r
576 // the stack didn't change last loop
\r
578 if (iCurrent==mStack.end())
\r
580 Syn_Printf("ERROR: CSynapseServer::Resolve, failed to resolve\n");
\r
584 if (ResolveAPI(*iCurrent))
\r
586 iCurrent = mStack.erase(iCurrent);
\r
587 mbStackChanged = true;
\r
592 // the stack changed at last loop
\r
593 mbStackChanged = false;
\r
594 iCurrent = mStack.begin();
\r
595 if (ResolveAPI(*iCurrent))
\r
597 iCurrent = mStack.erase(iCurrent);
\r
598 mbStackChanged = true;
\r
605 bool CSynapseServer::Resolve(CSynapseClient *pClient)
\r
607 bool ret = DoResolve(pClient);
\r
608 list<CSynapseClientSlot>::iterator iClient;
\r
609 iClient = mClients.begin();
\r
610 while(iClient != mClients.end())
\r
612 CSynapseClient *pClient = (*iClient).mpClient;
\r
613 if (!pClient->IsActive())
\r
615 Syn_Printf("Unloading an unused module: '%s'\n", pClient->GetInfo());
\r
616 iClient = ShutdownClient(iClient);
\r
624 void CSynapseServer::Shutdown()
\r
626 Syn_Printf("Synapse server core is shutting down\n");
\r
627 // do a first pass to shutdown the clients nicely (i.e. decref, release memory and drop everything)
\r
628 // 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
\r
629 list<CSynapseClientSlot>::iterator iClient;
\r
630 iClient = mClients.begin();
\r
631 for(iClient = mClients.begin(); iClient != mClients.end(); iClient++)
\r
633 (*iClient).mpClient->Shutdown();
\r
635 // now release them from the server's point of view
\r
636 iClient = mClients.begin();
\r
637 while(iClient != mClients.end())
\r
639 iClient = ShutdownClient(iClient);
\r
643 void CSynapseServer::DumpStack()
\r
645 list<APIDescriptor_t*>::iterator iCurrent;
\r
646 for(iCurrent=mStack.begin(); iCurrent != mStack.end(); iCurrent++)
\r
648 APIDescriptor_t*pAPI = *iCurrent;
\r
649 Syn_Printf("interface %s %p '%s' '%s'\n", APITypeName[pAPI->mType], pAPI, pAPI->major_name, pAPI->minor_name);
\r
653 void CSynapseServer::DumpActiveClients()
\r
655 list<CSynapseClientSlot>::iterator iClient;
\r
656 for(iClient=mClients.begin(); iClient!=mClients.end(); iClient++)
\r
658 CSynapseClient *pClient = (*iClient).mpClient;
\r
659 Syn_Printf("%s", pClient->GetInfo());
\r
660 if (pClient->IsActive())
\r
663 Syn_Printf(" (not active)\n");
\r
667 bool CSynapseServer::SelectClientConfig(const char *client_name)
\r
671 xmlNodePtr pNode = xmlDocGetRootElement(mpDoc);
\r
674 // look for the client
\r
675 pNode=pNode->children;
\r
678 if (pNode->type == XML_ELEMENT_NODE)
\r
680 xmlChar *prop = xmlGetProp(pNode, (const xmlChar *)"name");
\r
681 if (!strcmp((const char *)prop, client_name))
\r
688 pNode = pNode->next;
\r
691 return false; // config you asked for isn't there
\r
693 mpFocusedNode = pNode->children;
\r
694 mpCurrentClientConfig = pNode;
\r
698 bool CSynapseServer::GetNextConfig(char **api_name, char **minor)
\r
700 while(mpFocusedNode && mpFocusedNode->name)
\r
702 if (mpFocusedNode->type == XML_ELEMENT_NODE && !strcmp((const char *)mpFocusedNode->name, "api"))
\r
705 xmlFree(m_api_name);
\r
706 m_api_name = xmlGetProp(mpFocusedNode, (const xmlChar *)"name");
\r
707 *api_name = (char *)m_api_name;
\r
710 m_content = g_strdup((const gchar *)mpFocusedNode->children->content);
\r
711 g_strstrip(m_content);
\r
712 *minor = m_content;
\r
713 mpFocusedNode = mpFocusedNode->next;
\r
716 mpFocusedNode = mpFocusedNode->next;
\r
721 bool CSynapseServer::GetConfigForAPI( const char *api, char **minor ) {
\r
722 xmlNodePtr pNode = mpCurrentClientConfig->children;
\r
723 while ( pNode && pNode->name ) {
\r
724 if ( pNode->type == XML_ELEMENT_NODE && !strcmp( (const char *)pNode->name, "api" ) ) {
\r
725 if ( m_api_name ) {
\r
726 xmlFree( m_api_name );
\r
728 m_api_name = xmlGetProp( pNode, (const xmlChar *)"name" );
\r
729 if ( !strcmp( (const char *)m_api_name, api ) ) {
\r
731 g_free( m_content );
\r
733 m_content = g_strdup( (const gchar *)pNode->children->content );
\r
734 g_strstrip( m_content );
\r
735 *minor = m_content;
\r
739 pNode = pNode->next;
\r
744 const char *CSynapseServer::GetModuleFilename(CSynapseClient *pClient)
\r
746 list<CSynapseClientSlot>::iterator iSlot;
\r
747 for(iSlot=mClients.begin(); iSlot != mClients.end(); iSlot++)
\r
749 if ((*iSlot).mpClient == pClient)
\r
751 if ((*iSlot).mType == SYN_BUILTIN)
\r
753 return ""; // FIXME
\r
757 return (*iSlot).mFileName;
\r
765 =======================================================================
\r
767 =======================================================================
\r
770 CSynapseClient::CSynapseClient()
\r
774 void CSynapseClient::Shutdown()
\r
776 vector<APIDescriptor_t *>::iterator iAPI;
\r
777 for(iAPI=mAPIDescriptors.begin(); iAPI!=mAPIDescriptors.end(); iAPI++)
\r
779 APIDescriptor_t *pAPI = *iAPI;
\r
780 if (pAPI->mRefCount != 0)
\r
781 Syn_Printf("WARNING: ~CSynapseClient '%s' has non-zero ref count for interface '%s' '%s'\n", GetInfo(), pAPI->major_name, pAPI->minor_name);
\r
786 mAPIDescriptors.clear();
\r
787 vector<CSynapseAPIManager *>::iterator iManager;
\r
788 for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++)
\r
790 CSynapseAPIManager *pManager = *iManager;
\r
791 pManager->DecRef();
\r
794 mManagersList.clear();
\r
795 for(iManager=mManagersMatch.begin(); iManager!=mManagersMatch.end(); iManager++)
\r
797 CSynapseAPIManager *pManager = *iManager;
\r
798 pManager->DecRef();
\r
801 mManagersMatch.clear();
\r
804 CSynapseClient::~CSynapseClient()
\r
806 // this should not be doing anything when called from here if everything went right
\r
807 // otherwise it's likely to crash .. at least that's the sign we missed something
\r
811 int CSynapseClient::GetAPICount()
\r
813 return mAPIDescriptors.size();
\r
816 APIDescriptor_t* CSynapseClient::GetAPIDescriptor(int i)
\r
818 return mAPIDescriptors[i];
\r
821 int CSynapseClient::GetManagerMatchCount()
\r
823 return mManagersMatch.size();
\r
826 CSynapseAPIManager* CSynapseClient::GetManagerMatch(int i)
\r
828 return mManagersMatch[i];
\r
831 int CSynapseClient::GetManagerListCount()
\r
833 return mManagersList.size();
\r
836 CSynapseAPIManager* CSynapseClient::GetManagerList(int i)
\r
838 return mManagersList[i];
\r
841 bool CSynapseClient::AddAPI(const char *major, const char *minor, int size, EAPIType type, void *pTable)
\r
843 // do some safe checks before actual addition
\r
844 if (type == SYN_REQUIRE && !pTable)
\r
846 Syn_Printf("ERROR: interface '%s' '%s' from '%s' is SYN_REQUIRE and doesn't provide a function table pointer\n", major, minor, GetInfo());
\r
851 int *pi = (int *)pTable;
\r
854 Syn_Printf("ERROR: forgot to init function table size for interface '%s' '%s' from '%s'?\n", major, minor, GetInfo());
\r
858 APIDescriptor_t *pAPI = new APIDescriptor_t;
\r
859 memset(pAPI, 0, sizeof(APIDescriptor_t));
\r
860 strncpy(pAPI->major_name, major, MAX_APINAME);
\r
862 strncpy(pAPI->minor_name, minor, MAX_APINAME);
\r
863 pAPI->mType = type;
\r
864 pAPI->mpTable = pTable;
\r
865 // store the interface size
\r
866 if (type == SYN_PROVIDE)
\r
870 Syn_Printf("ERROR: size of the interface required for a SYN_PROVIDE ('%s' '%s' from '%s')\n", major, minor, GetInfo());
\r
874 pAPI->mSize = size;
\r
876 else if (type == SYN_REQUIRE)
\r
880 // if a non-zero value is given in function call, use this instead of the val in table
\r
881 *((int *)pAPI->mpTable) = size;
\r
882 pAPI->mSize = size;
\r
886 pAPI->mSize = *((int *)pAPI->mpTable);
\r
887 if (pAPI->mSize == 0)
\r
889 Syn_Printf("ERROR: didn't get an interface size ('%s' '%s' from '%s')\n", major, minor, GetInfo());
\r
897 Syn_Printf("ERROR: AddAPI type '%d' not supported\n", type);
\r
900 mAPIDescriptors.push_back(pAPI);
\r
901 #ifdef SYNAPSE_VERBOSE
\r
902 Syn_Printf("AddAPI: %s %p '%s' '%s' from '%s', size %d\n", APITypeName[pAPI->mType], pAPI, major, minor, GetInfo(), pAPI->mSize);
\r
907 #include "version.h"
\r
909 const char* CSynapseClient::GetInfo()
\r
911 return "CSynapseClient built " __DATE__ " " RADIANT_VERSION;
\r
914 bool CSynapseClient::CheckSetActive()
\r
918 int i,max=GetAPICount();
\r
919 for(i=0; i<max; i++)
\r
921 APIDescriptor_t *pAPI = GetAPIDescriptor(i);
\r
922 if (pAPI->mType == SYN_REQUIRE && !pAPI->mbTableInitDone)
\r
925 // if we have managers with fixed list, those need to be completely filled in too
\r
926 vector<CSynapseAPIManager *>::iterator iManager;
\r
927 for(iManager=mManagersList.begin(); iManager!=mManagersList.end(); iManager++)
\r
929 if (!(*iManager)->CheckSetActive())
\r
930 return false; // one of the managers doesn't have all it needs yet
\r
932 // call OnActivate to let the client perform last minute checks
\r
933 // NOTE: this should be fatal instead of letting the engine try other combinations
\r
934 if (!OnActivate()) {
\r
937 // yes, all required interfaces have been initialized
\r
938 Syn_Printf("'%s' activated\n", GetInfo());
\r
943 bool CSynapseClient::ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ) {
\r
945 if ( !client_name ) {
\r
946 client_name = GetName();
\r
949 Syn_Printf("Dynamic APIs for client '%s'\n", GetInfo());
\r
950 if ( !pServer->SelectClientConfig( client_name ) )
\r
952 Syn_Printf( "Failed to select synapse client config '%s'\n", client_name );
\r
957 while ( entries[i].type != SYN_UNKNOWN ) { // don't test pTable, for a SYN_PROVIDE it will be empty
\r
959 if ( !pServer->GetConfigForAPI( entries[i].api, &minor ) ) {
\r
960 Syn_Printf( "GetConfigForAPI '%s' failed - invalid XML config file?\n", entries[i].api );
\r
963 AddAPI( entries[i].api, minor, entries[i].size, entries[i].type, entries[i].pTable );
\r
966 Syn_Printf( "%d dynamic interfaces parsed for '%s'\n", i, client_name );
\r
970 void CSynapseClient::AddManager(CSynapseAPIManager *pManager)
\r
972 pManager->IncRef();
\r
973 if (pManager->GetType() == API_LIST)
\r
974 mManagersList.push_back(pManager);
\r
976 mManagersMatch.push_back(pManager);
\r
979 CSynapseAPIManager::~CSynapseAPIManager()
\r
981 vector<APIDescriptor_t *>::iterator iAPI;
\r
982 for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++)
\r
984 APIDescriptor_t *pAPI = *iAPI;
\r
985 if (pAPI->mRefCount != 0)
\r
987 Syn_Printf("WARNING: ~CSynapseAPIManager has non-zero ref count for interface '%s' '%s'\n", pAPI->major_name, pAPI->minor_name);
\r
994 APIDescriptor_t* CSynapseAPIManager::PrepareRequireAPI(APIDescriptor_t *pAPI)
\r
997 if (pAPI->mType != SYN_PROVIDE)
\r
999 Syn_Printf("ERROR: unexpected pAPI->mType != SYN_PROVIDE in CSynapseAPIManager::PrepareRequireAPI\n");
\r
1003 APIDescriptor_t *pRequireAPI = new APIDescriptor_t;
\r
1004 memcpy(pRequireAPI, pAPI, sizeof(APIDescriptor_t));
\r
1005 pRequireAPI->mType = SYN_REQUIRE_ANY;
\r
1006 pRequireAPI->mpTable = NULL;
\r
1007 pRequireAPI->mbTableInitDone = false;
\r
1008 pRequireAPI->mSize = 0; // this will have to be set correctly by the child for version checking
\r
1009 pRequireAPI->mRefCount = 0;
\r
1010 return pRequireAPI;
\r
1013 void CSynapseAPIManager::SetMatchAPI(const char *major, const char *minor)
\r
1015 if (strlen(minor)>MAX_PATTERN_STRING)
\r
1017 Syn_Printf("ERROR: MAX_TOKEN_STRING exceeded in CSynapseAPIManager::SetMatchAPI: '%s'\n", minor);
\r
1020 strcpy(major_pattern, major);
\r
1021 strcpy(minor_pattern, minor);
\r
1022 if (strcmp(minor, "*"))
\r
1028 bool CSynapseAPIManager::MatchAPI(const char *major, const char *minor)
\r
1030 assert(mType == API_MATCH);
\r
1033 if this interface has been allocated already, avoid requesting it again..
\r
1035 vector<APIDescriptor_t *>::iterator iAPI;
\r
1036 for(iAPI=mAPIs.begin(); iAPI!=mAPIs.end(); iAPI++)
\r
1038 if (CSynapseServer::MatchAPI((*iAPI)->major_name, (*iAPI)->minor_name, major, minor))
\r
1042 if (!strcmp(major, major_pattern))
\r
1047 bool CSynapseAPIManager::CheckSetActive()
\r
1049 if (mType == API_MATCH)
\r
1051 // mType == API_LIST
\r
1052 int i,max = GetAPICount();
\r
1053 for(i=0; i<max; i++)
\r
1055 if (!GetAPI(i)->mbTableInitDone)
\r
1061 void CSynapseAPIManager::InitializeAPIList()
\r
1063 char minor_tok[MAX_PATTERN_STRING];
\r
1068 Syn_Printf("WARNING: CSynapseAPIManager::InitializeAPIList on an already initialized APIManager\n");
\r
1072 strncpy(minor_tok, minor_pattern, MAX_PATTERN_STRING);
\r
1073 token = strtok(minor_tok, " ");
\r
1076 /* ask the child to build from scratch */
\r
1077 APIDescriptor_t *pAPI = new APIDescriptor_t;
\r
1078 memset(pAPI, 0, sizeof(APIDescriptor_t));
\r
1079 strncpy(pAPI->major_name, major_pattern, MAX_APINAME);
\r
1080 strncpy(pAPI->minor_name, token, MAX_APINAME);
\r
1081 pAPI->mType = SYN_REQUIRE_ANY;
\r
1082 FillAPITable(pAPI);
\r
1083 mAPIs.push_back(pAPI);
\r
1084 token = strtok(NULL, " ");
\r
1088 int CSynapseAPIManager::GetAPICount()
\r
1090 return mAPIs.size();
\r
1093 APIDescriptor_t* CSynapseAPIManager::GetAPI(int i)
\r
1098 // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=879
\r
1099 void fini_stub() {
\r
1100 printf( "fini_stub\n" );
\r