From def29cb7b48547c238cf64f58b3495ea0a5f860f Mon Sep 17 00:00:00 2001 From: Timothee 'TTimo' Besset Date: Sun, 16 Sep 2012 22:57:31 -0500 Subject: [PATCH] synapse: when using '*' for the minor, work extra hard to match with a single, already active provider. this fixes the problems related to having pk3 vfs and qlpk3 vfs both loaded for instance --- contrib/hydratoolz/plugin.cpp | 2 +- libs/synapse.h | 23 +++++++- libs/synapse/synapse.cpp | 98 ++++++++++++++++++++++++++++++----- plugins/eclassfgd/plugin.cpp | 2 +- plugins/imagehl/imagehl.cpp | 2 +- plugins/imagepng/plugin.cpp | 2 +- radiant/eclass_def.cpp | 2 +- 7 files changed, 111 insertions(+), 20 deletions(-) diff --git a/contrib/hydratoolz/plugin.cpp b/contrib/hydratoolz/plugin.cpp index bda4df2..4a5de38 100644 --- a/contrib/hydratoolz/plugin.cpp +++ b/contrib/hydratoolz/plugin.cpp @@ -387,7 +387,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons g_SynapseClient.AddAPI( PLUGIN_MAJOR, "HydraToolz", sizeof( _QERPluginTable ) ); g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); - g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable ); return &g_SynapseClient; } diff --git a/libs/synapse.h b/libs/synapse.h index f5b71fb..c400e8e 100644 --- a/libs/synapse.h +++ b/libs/synapse.h @@ -404,6 +404,11 @@ virtual bool OnActivate() { return true; } \return wether all APIs given were successfully found in the config */ bool ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ); + +/*! + search for a SYN_PROVIDE with that major in this client, return the index, or -1 if fail + */ +APIDescriptor_t * FindProvidesMajor( const char * major ) const; }; /*! @@ -607,8 +612,13 @@ virtual PFN_SYN_PRINTF_VA Get_Syn_Printf(); the minors have to be both NULL, or equal, or one the minors be '*' NOTE: the '*' minor should ONLY be used on an API that will be unique. It is hackish and kinda dangerous */ -static bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ); -static bool MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ); +bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ); +/*! + \return 0: not matching + \return 1: matching + \return 2: do extended checks for a minor of "*" + */ +static int MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ); #if defined( _WIN32 ) /*! @@ -655,6 +665,15 @@ bool GetConfigForAPI( const char *api, char **minor ); returns the filename of the module that the passed on client exists in */ const char *GetModuleFilename( CSynapseClient *pClient ); + +/*! + look for a client that is active, and provides a specific major + \return 0: not found + \return 1: single found + \return 2: multiple found + */ +int FindActiveMajorClient( const char * major, APIDescriptor_t ** ret ) const; + }; #endif diff --git a/libs/synapse/synapse.cpp b/libs/synapse/synapse.cpp index c4dd78c..ff7d787 100644 --- a/libs/synapse/synapse.cpp +++ b/libs/synapse/synapse.cpp @@ -424,23 +424,83 @@ void CSynapseServer::PushRequired( CSynapseClient *pClient ){ } } -bool CSynapseServer::MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ){ - return MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name ); +int CSynapseServer::FindActiveMajorClient( const char * major, APIDescriptor_t ** ret ) const { + Syn_Printf( "checking if we have a single active client for major \"%s\"\n", major ); + *ret = NULL; + list::const_iterator iClient; + for ( iClient = mClients.begin(); iClient != mClients.end(); iClient++ ) { + CSynapseClient *pClient = ( *iClient ).mpClient; + if ( !pClient->IsActive() ) { + continue; + } + APIDescriptor_t * found = pClient->FindProvidesMajor( major ); + if ( found == NULL ) { + continue; + } + Syn_Printf( " found in %s\n", pClient->GetInfo() ); + if ( *ret != NULL ) { + return 2; + } + *ret = found; + } + if ( *ret == NULL ) { + return 0; + } + return 1; } -bool CSynapseServer::MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ){ - if ( strcmp( major1, major2 ) ) { - return false; +bool CSynapseServer::MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ){ + int ret = MatchAPI( p1->major_name, p1->minor_name, p2->major_name, p2->minor_name ); + if ( ret == 2 ) { + // find out if we can resolve the minor "*" situation + APIDescriptor_t * any_minor_descriptor; + APIDescriptor_t * provider_descriptor; + if ( strcmp( p1->minor_name, "*" ) == 0 ) { + any_minor_descriptor = p1; + provider_descriptor = p2; + } else { + assert( strcmp( p2->minor_name, "*" ) == 0 ); + any_minor_descriptor = p2; + provider_descriptor = p1; + } + assert( any_minor_descriptor->mType == SYN_REQUIRE ); + assert( provider_descriptor->mType == SYN_PROVIDE ); + APIDescriptor_t * search_major; + int search_ret = FindActiveMajorClient( provider_descriptor->major_name, &search_major ); + if ( search_ret == 2 ) { + // FIXME: ERROR + Syn_Printf( "ERROR: Multiple modules active for major \"%s\": cannot resolve \"*\" for it\n", provider_descriptor->major_name ); + return false; + } + if ( search_ret == 0 ) { + // can't resolve yet + return false; + } + if ( search_major != provider_descriptor ) { + // the provider_descriptor we were passed is likely not active yet, so just ignore + return false; + } + return true; // this is a go, we have a unique match! + } + return ( ret != 0 ); +} + +int CSynapseServer::MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ){ + if ( strcmp( major1, major2 ) != 0 ) { + return 0; } // either no minor at all for this API, or matching - if ( ( minor1 && minor2 ) && !strcmp( minor1, minor2 ) ) { - return true; + if ( ( minor1 != NULL && minor2 != NULL ) && strcmp( minor1, minor2 ) == 0 ) { + return 1; } - // or one of the minors says "*" (knowing that the majors match already) - if ( ( minor1 && !strcmp( minor1, "*" ) ) || ( minor2 && !strcmp( minor2, "*" ) ) ) { - return true; + if ( ( minor1 != NULL && strcmp( minor1, "*" ) == 0 ) || ( minor2 != NULL && strcmp( minor2, "*" ) == 0 ) ) { + // one of the minors is "*", and the majors are matching + // there may be multiple SYN_PROVIDE for this major though, and we can't decide which with only this information + // e.g. "*" means "the one", not "any" (counter-intuitive, yeah) + // so let the caller know, maybe he'll figure it out + return 2; } - return false; + return 0; } bool CSynapseServer::ResolveAPI( APIDescriptor_t* pAPI ){ @@ -469,9 +529,9 @@ bool CSynapseServer::ResolveAPI( APIDescriptor_t* pAPI ){ continue; } // this is an active client, we can request - #ifdef SYNAPSE_VERBOSE +#ifdef SYNAPSE_VERBOSE Syn_Printf( "RequestAPI '%s' '%s' from '%s' for API %p\n", pAPI->major_name, pAPI->minor_name, pScanClient->GetInfo(), pAPI ); - #endif +#endif if ( !pScanClient->RequestAPI( pAPI ) ) { // this should never happen, means we think this module provides the API, but it answers that it doesn't Syn_Printf( "ERROR: RequestAPI failed\n" ); @@ -911,6 +971,18 @@ void CSynapseClient::AddManager( CSynapseAPIManager *pManager ){ } } +APIDescriptor_t * CSynapseClient::FindProvidesMajor( const char * major ) const { + int i,max = GetAPICount(); + for ( i = 0; i < max; i++ ) + { + APIDescriptor_t *pAPI = GetAPIDescriptor( i ); + if ( pAPI->mType == SYN_PROVIDE && strcmp( pAPI->major_name, major ) == 0 ) { + return pAPI; + } + } + return NULL; +} + CSynapseAPIManager::~CSynapseAPIManager(){ vector::iterator iAPI; for ( iAPI = mAPIs.begin(); iAPI != mAPIs.end(); iAPI++ ) diff --git a/plugins/eclassfgd/plugin.cpp b/plugins/eclassfgd/plugin.cpp index eb389d8..8c39bff 100644 --- a/plugins/eclassfgd/plugin.cpp +++ b/plugins/eclassfgd/plugin.cpp @@ -155,7 +155,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons g_SynapseClient.AddAPI( ECLASSMANAGER_MAJOR, NULL, sizeof( g_EClassManagerTable ), SYN_REQUIRE, &g_EClassManagerTable ); // Needs a 'default' option for this minor because we certainly don't load anything from wad files :) - g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically return &g_SynapseClient; } diff --git a/plugins/imagehl/imagehl.cpp b/plugins/imagehl/imagehl.cpp index 21b8a46..bbef360 100644 --- a/plugins/imagehl/imagehl.cpp +++ b/plugins/imagehl/imagehl.cpp @@ -75,7 +75,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons g_SynapseClient.AddAPI( IMAGE_MAJOR, "spr", sizeof( _QERPlugImageTable ) ); #endif // this "wad" needs to be "*" for the VFS, we don't care what VFS we have, as long as we have one. - g_SynapseClient.AddAPI( VFS_MAJOR, "wad", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); // wad, typically g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable ); return &g_SynapseClient; diff --git a/plugins/imagepng/plugin.cpp b/plugins/imagepng/plugin.cpp index 3f42a8f..b26a65b 100644 --- a/plugins/imagepng/plugin.cpp +++ b/plugins/imagepng/plugin.cpp @@ -63,7 +63,7 @@ extern "C" CSynapseClient * SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces( cons g_SynapseClient.AddAPI( IMAGE_MAJOR, "png", sizeof( _QERPlugImageTable ) ); g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( _QERFuncTable_1 ), SYN_REQUIRE, &g_FuncTable ); - g_SynapseClient.AddAPI( VFS_MAJOR, "pk3", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( _QERFileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); return &g_SynapseClient; } diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp index 0caf630..20d9040 100644 --- a/radiant/eclass_def.cpp +++ b/radiant/eclass_def.cpp @@ -62,7 +62,7 @@ void CSynapseBuiltinClientDef::EnumerateInterfaces( CSynapseServer *server ){ AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); AddAPI( ECLASSMANAGER_MAJOR, NULL, sizeof( g_EClassManagerTable ), SYN_REQUIRE, &g_EClassManagerTable ); // hardcode the minor for now, we can still add it to the synapse.config at some point - AddAPI( VFS_MAJOR, "pk3", sizeof( g_FileSystemTable_def ), SYN_REQUIRE, &g_FileSystemTable_def ); + AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable_def ), SYN_REQUIRE, &g_FileSystemTable_def ); AddAPI( ECLASS_MAJOR, "def", sizeof( _EClassTable ) ); }