Merge.
authorScott Ehlert <ds@alliedmods.net>
Mon Nov 24 08:39:46 2008 -0600 (2008-11-24)
changeset 242331f49899c0ae
parent 2422 9981b8ecf935
parent 2412 d8c659d4aae4
child 2424 d95d696a82e5
Merge.
core/msvc9/sourcemod_mm.vcproj
core/systems/ExtensionSys.cpp
core/systems/ExtensionSys.h
core/systems/ForwardSys.cpp
core/systems/ForwardSys.h
core/systems/HandleSys.cpp
core/systems/HandleSys.h
core/systems/LibrarySys.cpp
core/systems/LibrarySys.h
core/systems/PluginInfoDatabase.cpp
core/systems/PluginInfoDatabase.h
core/systems/PluginSys.cpp
core/systems/PluginSys.h
core/systems/ShareSys.cpp
core/systems/ShareSys.h
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/core/ExtensionSys.cpp	Mon Nov 24 08:39:46 2008 -0600
     1.3 @@ -0,0 +1,1208 @@
     1.4 +/**
     1.5 + * vim: set ts=4 :
     1.6 + * =============================================================================
     1.7 + * SourceMod
     1.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     1.9 + * =============================================================================
    1.10 + *
    1.11 + * This program is free software; you can redistribute it and/or modify it under
    1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 + * Free Software Foundation.
    1.14 + * 
    1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 + * details.
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License along with
    1.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 + *
    1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 + * or <http://www.sourcemod.net/license.php>.
    1.31 + *
    1.32 + * Version: $Id$
    1.33 + */
    1.34 +
    1.35 +#include <stdlib.h>
    1.36 +#include "ExtensionSys.h"
    1.37 +#include "LibrarySys.h"
    1.38 +#include "ShareSys.h"
    1.39 +#include "Logger.h"
    1.40 +#include "sourcemm_api.h"
    1.41 +#include "sm_srvcmds.h"
    1.42 +#include "sm_stringutil.h"
    1.43 +
    1.44 +CExtensionManager g_Extensions;
    1.45 +IdentityType_t g_ExtType;
    1.46 +
    1.47 +void CExtension::Initialize(const char *filename, const char *path)
    1.48 +{
    1.49 +	m_pAPI = NULL;
    1.50 +	m_pIdentToken = NULL;
    1.51 +	unload_code = 0;
    1.52 +	m_bFullyLoaded = false;
    1.53 +	m_File.assign(filename);
    1.54 +	m_Path.assign(path);
    1.55 +}
    1.56 +
    1.57 +CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
    1.58 +{
    1.59 +	Initialize(filename, path);
    1.60 +	m_pAPI = pAPI;
    1.61 +}
    1.62 +
    1.63 +CLocalExtension::CLocalExtension(const char *filename)
    1.64 +{
    1.65 +	m_PlId = 0;
    1.66 +	m_pLib = NULL;
    1.67 +
    1.68 +	char path[PLATFORM_MAX_PATH];
    1.69 +
    1.70 +	/* First see if there is an engine specific build! */
    1.71 +	g_SourceMod.BuildPath(Path_SM, 
    1.72 +		path, 
    1.73 +		PLATFORM_MAX_PATH, 
    1.74 +#if defined METAMOD_PLAPI_VERSION
    1.75 +#if defined ORANGEBOX_BUILD
    1.76 +		"extensions/auto.2.ep2/%s",
    1.77 +#else
    1.78 +		"extensions/auto.2.ep1/%s",
    1.79 +#endif //ORANGEBOX_BUILD
    1.80 +#else  //METAMOD_PLAPI_VERSION
    1.81 +		"extensions/auto.1.ep1/%s",
    1.82 +#endif //METAMOD_PLAPI_VERSION
    1.83 +		filename);
    1.84 +
    1.85 +	/* Try the "normal" version */
    1.86 +	if (!g_LibSys.IsPathFile(path))
    1.87 +	{
    1.88 +		g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
    1.89 +	}
    1.90 +
    1.91 +	Initialize(filename, path);
    1.92 +}
    1.93 +
    1.94 +bool CRemoteExtension::Load(char *error, size_t maxlength)
    1.95 +{
    1.96 +	if (!PerformAPICheck(error, maxlength))
    1.97 +	{
    1.98 +		m_pAPI = NULL;
    1.99 +		return false;
   1.100 +	}
   1.101 +
   1.102 +	if (!CExtension::Load(error, maxlength))
   1.103 +	{
   1.104 +		m_pAPI = NULL;
   1.105 +		return false;
   1.106 +	}
   1.107 +
   1.108 +	return true;
   1.109 +}
   1.110 +
   1.111 +bool CLocalExtension::Load(char *error, size_t maxlength)
   1.112 +{
   1.113 +	m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
   1.114 +
   1.115 +	if (m_pLib == NULL)
   1.116 +	{
   1.117 +		return false;
   1.118 +	}
   1.119 +
   1.120 +	typedef IExtensionInterface *(*GETAPI)();
   1.121 +	GETAPI pfnGetAPI = NULL;
   1.122 +
   1.123 +	if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
   1.124 +	{
   1.125 +		m_pLib->CloseLibrary();
   1.126 +		m_pLib = NULL;
   1.127 +		snprintf(error, maxlength, "Unable to find extension entry point");
   1.128 +		return false;
   1.129 +	}
   1.130 +
   1.131 +	m_pAPI = pfnGetAPI();
   1.132 +
   1.133 +	/* Check pointer and version */
   1.134 +	if (!PerformAPICheck(error, maxlength))
   1.135 +	{
   1.136 +		m_pLib->CloseLibrary();
   1.137 +		m_pLib = NULL;
   1.138 +		m_pAPI = NULL;
   1.139 +		return false;
   1.140 +	}
   1.141 +
   1.142 +	/* Load as MM:S */
   1.143 +	if (m_pAPI->IsMetamodExtension())
   1.144 +	{
   1.145 +		bool already;
   1.146 +		m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
   1.147 +	}
   1.148 +
   1.149 +	if (!CExtension::Load(error, maxlength))
   1.150 +	{
   1.151 +		if (m_pAPI->IsMetamodExtension())
   1.152 +		{
   1.153 +			if (m_PlId)
   1.154 +			{
   1.155 +				char dummy[255];
   1.156 +				g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
   1.157 +				m_PlId = 0;
   1.158 +			}
   1.159 +		}
   1.160 +		m_pLib->CloseLibrary();
   1.161 +		m_pLib = NULL;
   1.162 +		m_pAPI = NULL;
   1.163 +		return false;
   1.164 +	}
   1.165 +
   1.166 +	return true;
   1.167 +}
   1.168 +
   1.169 +void CRemoteExtension::Unload()
   1.170 +{
   1.171 +}
   1.172 +
   1.173 +void CLocalExtension::Unload()
   1.174 +{
   1.175 +	if (m_pAPI != NULL && m_PlId)
   1.176 +	{
   1.177 +		char temp_buffer[255];
   1.178 +		g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
   1.179 +		m_PlId = 0;
   1.180 +	}
   1.181 +
   1.182 +	if (m_pLib != NULL)
   1.183 +	{
   1.184 +		m_pLib->CloseLibrary();
   1.185 +		m_pLib = NULL;
   1.186 +	}
   1.187 +}
   1.188 +
   1.189 +bool CRemoteExtension::IsExternal()
   1.190 +{
   1.191 +	return true;
   1.192 +}
   1.193 +
   1.194 +bool CLocalExtension::IsExternal()
   1.195 +{
   1.196 +	return false;
   1.197 +}
   1.198 +
   1.199 +CExtension::~CExtension()
   1.200 +{
   1.201 +	DestroyIdentity();
   1.202 +}
   1.203 +
   1.204 +bool CExtension::PerformAPICheck(char *error, size_t maxlength)
   1.205 +{
   1.206 +	if (!m_pAPI)
   1.207 +	{
   1.208 +		snprintf(error, maxlength, "No IExtensionInterface instance provided");
   1.209 +		return false;
   1.210 +	}
   1.211 +	
   1.212 +	if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
   1.213 +	{
   1.214 +		snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
   1.215 +		return false;
   1.216 +	}
   1.217 +
   1.218 +	return true;
   1.219 +}
   1.220 +
   1.221 +bool CExtension::Load(char *error, size_t maxlength)
   1.222 +{
   1.223 +	CreateIdentity();
   1.224 +	if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
   1.225 +	{
   1.226 +		DestroyIdentity();
   1.227 +		return false;
   1.228 +	}
   1.229 +	else
   1.230 +	{
   1.231 +		/* Check if we're past load time */
   1.232 +		if (!g_SourceMod.IsMapLoading())
   1.233 +		{
   1.234 +			m_pAPI->OnExtensionsAllLoaded();
   1.235 +		}
   1.236 +	}
   1.237 +
   1.238 +	return true;
   1.239 +}
   1.240 +
   1.241 +void CExtension::CreateIdentity()
   1.242 +{
   1.243 +	if (m_pIdentToken != NULL)
   1.244 +	{
   1.245 +		return;
   1.246 +	}
   1.247 +
   1.248 +	m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
   1.249 +}
   1.250 +
   1.251 +void CExtension::DestroyIdentity()
   1.252 +{
   1.253 +	if (m_pIdentToken == NULL)
   1.254 +	{
   1.255 +		return;
   1.256 +	}
   1.257 +
   1.258 +	g_ShareSys.DestroyIdentity(m_pIdentToken);
   1.259 +	m_pIdentToken = NULL;
   1.260 +}
   1.261 +
   1.262 +void CExtension::MarkAllLoaded()
   1.263 +{
   1.264 +	assert(m_bFullyLoaded == false);
   1.265 +	if (!m_bFullyLoaded)
   1.266 +	{
   1.267 +		m_bFullyLoaded = true;
   1.268 +		m_pAPI->OnExtensionsAllLoaded();
   1.269 +	}
   1.270 +}
   1.271 +
   1.272 +void CExtension::AddPlugin(CPlugin *pPlugin)
   1.273 +{
   1.274 +	/* Unfortunately we have to do this :( */
   1.275 +	if (m_Dependents.find(pPlugin) != m_Dependents.end())
   1.276 +	{
   1.277 +		m_Dependents.push_back(pPlugin);
   1.278 +	}
   1.279 +}
   1.280 +
   1.281 +void CExtension::SetError(const char *error)
   1.282 +{
   1.283 +	m_Error.assign(error);
   1.284 +}
   1.285 +
   1.286 +IExtensionInterface *CExtension::GetAPI()
   1.287 +{
   1.288 +	return m_pAPI;
   1.289 +}
   1.290 +
   1.291 +const char *CExtension::GetFilename()
   1.292 +{
   1.293 +	return m_File.c_str();
   1.294 +}
   1.295 +
   1.296 +IdentityToken_t *CExtension::GetIdentity()
   1.297 +{
   1.298 +	return m_pIdentToken;
   1.299 +}
   1.300 +
   1.301 +bool CRemoteExtension::IsLoaded()
   1.302 +{
   1.303 +	return (m_pAPI != NULL);
   1.304 +}
   1.305 +
   1.306 +bool CLocalExtension::IsLoaded()
   1.307 +{
   1.308 +	return (m_pLib != NULL);
   1.309 +}
   1.310 +
   1.311 +void CExtension::AddDependency(const IfaceInfo *pInfo)
   1.312 +{
   1.313 +	if (m_Deps.find(*pInfo) == m_Deps.end())
   1.314 +	{
   1.315 +		m_Deps.push_back(*pInfo);
   1.316 +	}
   1.317 +}
   1.318 +
   1.319 +bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
   1.320 +{
   1.321 +	return (i1.iface == i2.iface) && (i1.owner == i2.owner);
   1.322 +}
   1.323 +
   1.324 +void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
   1.325 +{
   1.326 +	IfaceInfo info;
   1.327 +	info.iface = iface;
   1.328 +	info.owner = pOther;
   1.329 +
   1.330 +	List<IfaceInfo>::iterator iter;
   1.331 +	for (iter = m_ChildDeps.begin();
   1.332 +		 iter != m_ChildDeps.end();
   1.333 +		 iter++)
   1.334 +	{
   1.335 +		IfaceInfo &other = (*iter);
   1.336 +		if (other == info)
   1.337 +		{
   1.338 +			return;
   1.339 +		}
   1.340 +	}
   1.341 +
   1.342 +	m_ChildDeps.push_back(info);
   1.343 +}
   1.344 +
   1.345 +ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
   1.346 +{
   1.347 +	List<IfaceInfo>::iterator iter = m_Deps.begin();
   1.348 +
   1.349 +	if (iter == m_Deps.end())
   1.350 +	{
   1.351 +		return NULL;
   1.352 +	}
   1.353 +
   1.354 +	if (pOwner)
   1.355 +	{
   1.356 +		*pOwner = (*iter).owner;
   1.357 +	}
   1.358 +	if (pInterface)
   1.359 +	{
   1.360 +		*pInterface = (*iter).iface;
   1.361 +	}
   1.362 +
   1.363 +	List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
   1.364 +
   1.365 +	return (ITERATOR *)pIter;
   1.366 +}
   1.367 +
   1.368 +bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
   1.369 +{
   1.370 +	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
   1.371 +	List<IfaceInfo>::iterator _iter;
   1.372 +
   1.373 +	if (_iter == m_Deps.end())
   1.374 +	{
   1.375 +		return false;
   1.376 +	}
   1.377 +
   1.378 +	_iter++;
   1.379 +
   1.380 +	if (pOwner)
   1.381 +	{
   1.382 +		*pOwner = (*_iter).owner;
   1.383 +	}
   1.384 +	if (pInterface)
   1.385 +	{
   1.386 +		*pInterface = (*_iter).iface;
   1.387 +	}
   1.388 +
   1.389 +	*pIter = _iter;
   1.390 +
   1.391 +	if (_iter == m_Deps.end())
   1.392 +	{
   1.393 +		return false;
   1.394 +	}
   1.395 +
   1.396 +	return true;
   1.397 +}
   1.398 +
   1.399 +void CExtension::FreeDependencyIterator(ITERATOR *iter)
   1.400 +{
   1.401 +	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
   1.402 +
   1.403 +	delete pIter;
   1.404 +}
   1.405 +
   1.406 +void CExtension::AddInterface(SMInterface *pInterface)
   1.407 +{
   1.408 +	m_Interfaces.push_back(pInterface);
   1.409 +}
   1.410 +
   1.411 +bool CExtension::IsRunning(char *error, size_t maxlength)
   1.412 +{
   1.413 +	if (!IsLoaded())
   1.414 +	{
   1.415 +		if (error)
   1.416 +		{
   1.417 +			snprintf(error, maxlength, "%s", m_Error.c_str());
   1.418 +		}
   1.419 +		return false;
   1.420 +	}
   1.421 +
   1.422 +	return m_pAPI->QueryRunning(error, maxlength);
   1.423 +}
   1.424 +
   1.425 +void CExtension::AddLibrary(const char *library)
   1.426 +{
   1.427 +	m_Libraries.push_back(library);
   1.428 +}
   1.429 +
   1.430 +/*********************
   1.431 + * EXTENSION MANAGER *
   1.432 + *********************/
   1.433 +
   1.434 +void CExtensionManager::OnSourceModAllInitialized()
   1.435 +{
   1.436 +	g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
   1.437 +	g_PluginSys.AddPluginsListener(this);
   1.438 +	g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
   1.439 +	g_ShareSys.AddInterface(NULL, this);
   1.440 +}
   1.441 +
   1.442 +void CExtensionManager::OnSourceModShutdown()
   1.443 +{
   1.444 +	g_RootMenu.RemoveRootConsoleCommand("exts", this);
   1.445 +	g_ShareSys.DestroyIdentType(g_ExtType);
   1.446 +}
   1.447 +
   1.448 +void CExtensionManager::Shutdown()
   1.449 +{
   1.450 +	List<CExtension *>::iterator iter;
   1.451 +
   1.452 +	while ((iter = m_Libs.begin()) != m_Libs.end())
   1.453 +	{
   1.454 +		UnloadExtension((*iter));
   1.455 +	}
   1.456 +}
   1.457 +
   1.458 +void CExtensionManager::TryAutoload()
   1.459 +{
   1.460 +	char path[PLATFORM_MAX_PATH];
   1.461 +
   1.462 +	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
   1.463 +
   1.464 +	IDirectory *pDir = g_LibSys.OpenDirectory(path);
   1.465 +	if (!pDir)
   1.466 +	{
   1.467 +		return;
   1.468 +	}
   1.469 +
   1.470 +	const char *lfile;
   1.471 +	size_t len;
   1.472 +	while (pDir->MoreFiles())
   1.473 +	{
   1.474 +		if (pDir->IsEntryDirectory())
   1.475 +		{
   1.476 +			pDir->NextEntry();
   1.477 +			continue;
   1.478 +		}
   1.479 +
   1.480 +		lfile = pDir->GetEntryName();
   1.481 +		len = strlen(lfile);
   1.482 +		if (len <= 9) /* size of ".autoload" */
   1.483 +		{
   1.484 +			pDir->NextEntry();
   1.485 +			continue;
   1.486 +		}
   1.487 +
   1.488 +		if (strcmp(&lfile[len - 9], ".autoload") != 0)
   1.489 +		{
   1.490 +			pDir->NextEntry();
   1.491 +			continue;
   1.492 +		}
   1.493 +
   1.494 +		char file[PLATFORM_MAX_PATH];
   1.495 +		len = UTIL_Format(file, sizeof(file), "%s", lfile);
   1.496 +		strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
   1.497 +
   1.498 +		LoadAutoExtension(file);
   1.499 +		
   1.500 +		pDir->NextEntry();
   1.501 +	}
   1.502 +}
   1.503 +
   1.504 +IExtension *CExtensionManager::LoadAutoExtension(const char *path)
   1.505 +{
   1.506 +	if (!strstr(path, "." PLATFORM_LIB_EXT))
   1.507 +	{
   1.508 +		char newpath[PLATFORM_MAX_PATH];
   1.509 +		g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
   1.510 +		return LoadAutoExtension(newpath);
   1.511 +	}
   1.512 +
   1.513 +	IExtension *pAlready;
   1.514 +	if ((pAlready=FindExtensionByFile(path)) != NULL)
   1.515 +	{
   1.516 +		return pAlready;
   1.517 +	}
   1.518 +
   1.519 +	char error[256];
   1.520 +	CExtension *p = new CLocalExtension(path);
   1.521 +
   1.522 +	/* We put us in the list beforehand so extensions that check for each other
   1.523 +	 * won't recursively load each other.
   1.524 +	 */
   1.525 +	m_Libs.push_back(p);
   1.526 +
   1.527 +	if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
   1.528 +	{
   1.529 +		g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
   1.530 +		p->SetError(error);
   1.531 +	}
   1.532 +
   1.533 +	return p;
   1.534 +}
   1.535 +
   1.536 +IExtension *CExtensionManager::FindExtensionByFile(const char *file)
   1.537 +{
   1.538 +	List<CExtension *>::iterator iter;
   1.539 +	CExtension *pExt;
   1.540 +
   1.541 +	/* Chomp off the path */
   1.542 +	char lookup[PLATFORM_MAX_PATH];
   1.543 +	g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
   1.544 +
   1.545 +	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
   1.546 +	{
   1.547 +		pExt = (*iter);
   1.548 +		char short_file[PLATFORM_MAX_PATH];
   1.549 +		g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
   1.550 +		if (strcmp(lookup, short_file) == 0)
   1.551 +		{
   1.552 +			return pExt;
   1.553 +		}
   1.554 +	}
   1.555 +
   1.556 +	/* If we got no results, test if there was a platform extension.
   1.557 +	 * If not, add one.
   1.558 +	 */
   1.559 +	if (!strstr(file, "." PLATFORM_LIB_EXT))
   1.560 +	{
   1.561 +		char path[PLATFORM_MAX_PATH];
   1.562 +		UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
   1.563 +		return FindExtensionByFile(path);
   1.564 +	}
   1.565 +
   1.566 +	return NULL;
   1.567 +}
   1.568 +
   1.569 +IExtension *CExtensionManager::FindExtensionByName(const char *ext)
   1.570 +{
   1.571 +	List<CExtension *>::iterator iter;
   1.572 +	CExtension *pExt;
   1.573 +	IExtensionInterface *pAPI;
   1.574 +	const char *name;
   1.575 +
   1.576 +	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
   1.577 +	{
   1.578 +		pExt = (*iter);
   1.579 +		if (!pExt->IsLoaded())
   1.580 +		{
   1.581 +			continue;
   1.582 +		}
   1.583 +		if ((pAPI = pExt->GetAPI()) == NULL)
   1.584 +		{
   1.585 +			continue;
   1.586 +		}
   1.587 +		name = pAPI->GetExtensionName();
   1.588 +		if (!name)
   1.589 +		{
   1.590 +			continue;
   1.591 +		}
   1.592 +		if (strcmp(name, ext) == 0)
   1.593 +		{
   1.594 +			return pExt;
   1.595 +		}
   1.596 +	}
   1.597 +
   1.598 +	return NULL;
   1.599 +}
   1.600 +
   1.601 +IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
   1.602 +{
   1.603 +	IExtension *pAlready;
   1.604 +	if ((pAlready=FindExtensionByFile(file)) != NULL)
   1.605 +	{
   1.606 +		return pAlready;
   1.607 +	}
   1.608 +
   1.609 +	CExtension *pExt = new CLocalExtension(file);
   1.610 +
   1.611 +	if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
   1.612 +	{
   1.613 +		pExt->Unload();
   1.614 +		delete pExt;
   1.615 +		return NULL;
   1.616 +	}
   1.617 +
   1.618 +	/* :TODO: do QueryRunning check if the map is loaded */
   1.619 +
   1.620 +	m_Libs.push_back(pExt);
   1.621 +
   1.622 +	return pExt;
   1.623 +}
   1.624 +
   1.625 +void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
   1.626 +{
   1.627 +	CExtension *pExt = (CExtension *)pRequester;
   1.628 +	CExtension *pOwner = (CExtension *)pInfo->owner;
   1.629 +
   1.630 +	pExt->AddDependency(pInfo);
   1.631 +
   1.632 +	IExtensionInterface *pAPI = pExt->GetAPI();
   1.633 +	if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
   1.634 +	{
   1.635 +		pOwner->AddChildDependent(pExt, pInfo->iface);
   1.636 +	}
   1.637 +}
   1.638 +
   1.639 +void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface)
   1.640 +{
   1.641 +	CExtension *pExt = (CExtension *)ext;
   1.642 +	CExtension *pOwner = GetExtensionFromIdent(other);
   1.643 +
   1.644 +	IfaceInfo info;
   1.645 +
   1.646 +	info.iface = (SMInterface *)iface;
   1.647 +	info.owner = pOwner;
   1.648 +
   1.649 +	pExt->AddDependency(&info);
   1.650 +	pOwner->AddChildDependent(pExt, (SMInterface *)iface);
   1.651 +}
   1.652 +
   1.653 +void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
   1.654 +{
   1.655 +	CExtension *pExt = (CExtension *)pOwner;
   1.656 +
   1.657 +	pExt->AddInterface(pInterface);
   1.658 +}
   1.659 +
   1.660 +void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
   1.661 +{
   1.662 +	CExtension *pExt = (CExtension *)pParent;
   1.663 +
   1.664 +	pExt->AddPlugin(pPlugin);
   1.665 +}
   1.666 +
   1.667 +void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
   1.668 +{
   1.669 +	List<CExtension *>::iterator iter;
   1.670 +
   1.671 +	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
   1.672 +	{
   1.673 +		(*iter)->DropRefsTo((CPlugin *)plugin);
   1.674 +	}
   1.675 +}
   1.676 +
   1.677 +CExtension *CExtensionManager::FindByOrder(unsigned int num)
   1.678 +{
   1.679 +	if (num < 1 || num > m_Libs.size())
   1.680 +	{
   1.681 +		return NULL;
   1.682 +	}
   1.683 +
   1.684 +	List<CExtension *>::iterator iter = m_Libs.begin();
   1.685 +
   1.686 +	while (iter != m_Libs.end())
   1.687 +	{
   1.688 +		if (--num == 0)
   1.689 +		{
   1.690 +			return (*iter);
   1.691 +		}
   1.692 +		iter++;
   1.693 +	}
   1.694 +
   1.695 +	return NULL;
   1.696 +}
   1.697 +
   1.698 +bool CExtensionManager::UnloadExtension(IExtension *_pExt)
   1.699 +{
   1.700 +	if (!_pExt)
   1.701 +	{
   1.702 +		return false;
   1.703 +	}
   1.704 +
   1.705 +	CExtension *pExt = (CExtension *)_pExt;
   1.706 +
   1.707 +	if (m_Libs.find(pExt) == m_Libs.end())
   1.708 +	{
   1.709 +		return false;
   1.710 +	}
   1.711 +
   1.712 +	/* First remove us from internal lists */
   1.713 +	g_ShareSys.RemoveInterfaces(_pExt);
   1.714 +	m_Libs.remove(pExt);
   1.715 +
   1.716 +	List<CExtension *> UnloadQueue;
   1.717 +
   1.718 +	/* Handle dependencies */
   1.719 +	if (pExt->IsLoaded())
   1.720 +	{
   1.721 +		/* Unload any dependent plugins */
   1.722 +		List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
   1.723 +		while (p_iter != pExt->m_Dependents.end())
   1.724 +		{
   1.725 +			/* We have to manually unlink ourselves here, since we're no longer being managed */
   1.726 +			g_PluginSys.UnloadPlugin((*p_iter));
   1.727 +			p_iter = pExt->m_Dependents.erase(p_iter);
   1.728 +		}
   1.729 +
   1.730 +		List<String>::iterator s_iter;
   1.731 +		for (s_iter = pExt->m_Libraries.begin();
   1.732 +			 s_iter != pExt->m_Libraries.end();
   1.733 +			 s_iter++)
   1.734 +		{
   1.735 +			g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
   1.736 +		}
   1.737 +
   1.738 +		/* Notify and/or unload all dependencies */
   1.739 +		List<CExtension *>::iterator c_iter;
   1.740 +		CExtension *pDep;
   1.741 +		IExtensionInterface *pAPI;
   1.742 +		for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
   1.743 +		{
   1.744 +			pDep = (*c_iter);
   1.745 +			if ((pAPI=pDep->GetAPI()) == NULL)
   1.746 +			{
   1.747 +				continue;
   1.748 +			}
   1.749 +			if (pDep == pExt)
   1.750 +			{
   1.751 +				continue;
   1.752 +			}
   1.753 +			/* Now, get its dependency list */
   1.754 +			bool dropped = false;
   1.755 +			List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
   1.756 +			while (i_iter != pDep->m_Deps.end())
   1.757 +			{
   1.758 +				if ((*i_iter).owner == _pExt)
   1.759 +				{
   1.760 +					if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
   1.761 +					{
   1.762 +						if (!dropped)
   1.763 +						{
   1.764 +							dropped = true;
   1.765 +							UnloadQueue.push_back(pDep);
   1.766 +						}
   1.767 +					}
   1.768 +					pAPI->NotifyInterfaceDrop((*i_iter).iface);
   1.769 +					i_iter = pDep->m_Deps.erase(i_iter);
   1.770 +				}
   1.771 +				else
   1.772 +				{
   1.773 +					i_iter++;
   1.774 +				}
   1.775 +			}
   1.776 +			/* Flush out any back references to this plugin */
   1.777 +			i_iter = pDep->m_ChildDeps.begin();
   1.778 +			while (i_iter != pDep->m_ChildDeps.end())
   1.779 +			{
   1.780 +				if ((*i_iter).owner == pExt)
   1.781 +				{
   1.782 +					i_iter = pDep->m_ChildDeps.erase(i_iter);
   1.783 +				}
   1.784 +				else
   1.785 +				{
   1.786 +					i_iter++;
   1.787 +				}
   1.788 +			}
   1.789 +		}
   1.790 +
   1.791 +		/* Unbind our natives from Core */
   1.792 +		pExt->DropEverything();
   1.793 +	}
   1.794 +
   1.795 +	IdentityToken_t *pIdentity;
   1.796 +	if ((pIdentity = pExt->GetIdentity()) != NULL)
   1.797 +	{
   1.798 +		SMGlobalClass *glob = SMGlobalClass::head;
   1.799 +		while (glob)
   1.800 +		{
   1.801 +			glob->OnSourceModIdentityDropped(pIdentity);
   1.802 +			glob = glob->m_pGlobalClassNext;
   1.803 +		}
   1.804 +	}
   1.805 +
   1.806 +	/* Tell it to unload */
   1.807 +	if (pExt->IsLoaded())
   1.808 +	{
   1.809 +		IExtensionInterface *pAPI = pExt->GetAPI();
   1.810 +		pAPI->OnExtensionUnload();
   1.811 +	}
   1.812 +
   1.813 +	pExt->Unload();
   1.814 +	delete pExt;
   1.815 +
   1.816 +	List<CExtension *>::iterator iter;
   1.817 +	for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
   1.818 +	{
   1.819 +		/* NOTE: This is safe because the unload function backs out of anything not present */
   1.820 +		UnloadExtension((*iter));
   1.821 +	}
   1.822 +
   1.823 +	return true;
   1.824 +}
   1.825 +
   1.826 +void CExtensionManager::MarkAllLoaded()
   1.827 +{
   1.828 +	List<CExtension *>::iterator iter;
   1.829 +	CExtension *pExt;
   1.830 +
   1.831 +	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
   1.832 +	{
   1.833 +		pExt = (*iter);
   1.834 +		if (!pExt->IsLoaded())
   1.835 +		{
   1.836 +			continue;
   1.837 +		}
   1.838 +		if (pExt->m_bFullyLoaded)
   1.839 +		{
   1.840 +			continue;
   1.841 +		}
   1.842 +		pExt->MarkAllLoaded();
   1.843 +	}
   1.844 +}
   1.845 +
   1.846 +void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
   1.847 +{
   1.848 +	/* This function doesn't really need to do anything now.  We make sure the 
   1.849 +	 * other extension is loaded, but handling of dependencies is really done 
   1.850 +	 * by the interface fetcher.
   1.851 +	 */
   1.852 +	if (required || autoload)
   1.853 +	{
   1.854 +		LoadAutoExtension(file);
   1.855 +	}
   1.856 +}
   1.857 +
   1.858 +void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   1.859 +{
   1.860 +	int argcount = command.ArgC();
   1.861 +	if (argcount >= 3)
   1.862 +	{
   1.863 +		const char *cmd = command.Arg(2);
   1.864 +		if (strcmp(cmd, "list") == 0)
   1.865 +		{
   1.866 +			List<CExtension *>::iterator iter;
   1.867 +			CExtension *pExt;
   1.868 +			unsigned int num = 1;
   1.869 +			switch (m_Libs.size())
   1.870 +			{
   1.871 +			case 1:
   1.872 +				{
   1.873 +					g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
   1.874 +					break;
   1.875 +				}
   1.876 +			case 0:
   1.877 +				{
   1.878 +					g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
   1.879 +					break;
   1.880 +				}
   1.881 +			default:
   1.882 +				{
   1.883 +					g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
   1.884 +					break;
   1.885 +				}
   1.886 +			}
   1.887 +			for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
   1.888 +			{
   1.889 +				pExt = (*iter);
   1.890 +				if (pExt->IsLoaded())
   1.891 +				{
   1.892 +					char error[255];
   1.893 +					if (!pExt->IsRunning(error, sizeof(error)))
   1.894 +					{
   1.895 +						g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
   1.896 +					}
   1.897 +					else
   1.898 +					{
   1.899 +						IExtensionInterface *pAPI = pExt->GetAPI();
   1.900 +						const char *name = pAPI->GetExtensionName();
   1.901 +						const char *version = pAPI->GetExtensionVerString();
   1.902 +						const char *descr = pAPI->GetExtensionDescription();
   1.903 +						g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
   1.904 +					}
   1.905 +				} else {
   1.906 +					g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
   1.907 +				}
   1.908 +			}
   1.909 +			return;
   1.910 +		}
   1.911 +		else if (strcmp(cmd, "info") == 0)
   1.912 +		{
   1.913 +			if (argcount < 4)
   1.914 +			{
   1.915 +				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
   1.916 +				return;
   1.917 +			}
   1.918 +
   1.919 +			const char *sId = command.Arg(3);
   1.920 +			unsigned int id = atoi(sId);
   1.921 +			if (id <= 0)
   1.922 +			{
   1.923 +				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
   1.924 +				return;
   1.925 +			}
   1.926 +
   1.927 +			if (m_Libs.size() == 0)
   1.928 +			{
   1.929 +				g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
   1.930 +				return;
   1.931 +			}
   1.932 +
   1.933 +			if (id > m_Libs.size())
   1.934 +			{
   1.935 +				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
   1.936 +				return;
   1.937 +			}
   1.938 +
   1.939 +			List<CExtension *>::iterator iter = m_Libs.begin();
   1.940 +			CExtension *pExt = NULL;
   1.941 +			while (iter != m_Libs.end())
   1.942 +			{
   1.943 +				if (--id == 0)
   1.944 +				{
   1.945 +					pExt = (*iter);
   1.946 +					break;
   1.947 +				}
   1.948 +				iter++;
   1.949 +			}
   1.950 +			/* This should never happen */
   1.951 +			if (!pExt)
   1.952 +			{
   1.953 +				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
   1.954 +				return;
   1.955 +			}
   1.956 +
   1.957 +			if (!pExt->IsLoaded())
   1.958 +			{
   1.959 +				g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
   1.960 +				g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
   1.961 +			}
   1.962 +			else
   1.963 +			{
   1.964 +				char error[255];
   1.965 +				if (!pExt->IsRunning(error, sizeof(error)))
   1.966 +				{
   1.967 +					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
   1.968 +					g_RootMenu.ConsolePrint(" Loaded: Yes");
   1.969 +					g_RootMenu.ConsolePrint(" Running: No (%s)", error);
   1.970 +				}
   1.971 +				else
   1.972 +				{
   1.973 +					IExtensionInterface *pAPI = pExt->GetAPI();
   1.974 +					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
   1.975 +					g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
   1.976 +					g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
   1.977 +					g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
   1.978 +					g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
   1.979 +
   1.980 +					if (pExt->IsExternal())
   1.981 +					{
   1.982 +						g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
   1.983 +					}
   1.984 +					else if (pAPI->IsMetamodExtension())
   1.985 +					{
   1.986 +						g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
   1.987 +					}
   1.988 +					else
   1.989 +					{
   1.990 +						g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
   1.991 +					}
   1.992 +				}
   1.993 +			}
   1.994 +			return;
   1.995 +		}
   1.996 +		else if (strcmp(cmd, "unload") == 0)
   1.997 +		{
   1.998 +			if (argcount < 4)
   1.999 +			{
  1.1000 +				g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
  1.1001 +				return;
  1.1002 +			}
  1.1003 +
  1.1004 +			const char *arg = command.Arg(3);
  1.1005 +			unsigned int num = atoi(arg);
  1.1006 +			CExtension *pExt = FindByOrder(num);
  1.1007 +
  1.1008 +			if (!pExt)
  1.1009 +			{
  1.1010 +				g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
  1.1011 +				return;
  1.1012 +			}
  1.1013 +
  1.1014 +			if (argcount > 4 && pExt->unload_code)
  1.1015 +			{
  1.1016 +				const char *unload = command.Arg(4);
  1.1017 +				if (pExt->unload_code == (unsigned)atoi(unload))
  1.1018 +				{
  1.1019 +					char filename[PLATFORM_MAX_PATH];
  1.1020 +					snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
  1.1021 +					UnloadExtension(pExt);
  1.1022 +					g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
  1.1023 +				}
  1.1024 +				else
  1.1025 +				{
  1.1026 +					g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
  1.1027 +				}
  1.1028 +				return;
  1.1029 +			}
  1.1030 +
  1.1031 +			if (!pExt->IsLoaded() 
  1.1032 +				|| (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
  1.1033 +			{
  1.1034 +				char filename[PLATFORM_MAX_PATH];
  1.1035 +				snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
  1.1036 +				UnloadExtension(pExt);
  1.1037 +				g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
  1.1038 +				return;
  1.1039 +			}
  1.1040 +			else
  1.1041 +			{
  1.1042 +				List<CPlugin *> plugins;
  1.1043 +				if (pExt->m_ChildDeps.size())
  1.1044 +				{
  1.1045 +					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
  1.1046 +					List<CExtension *>::iterator iter;
  1.1047 +					CExtension *pOther;
  1.1048 +					/* Get list of all extensions */
  1.1049 +					for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  1.1050 +					{
  1.1051 +						List<IfaceInfo>::iterator i_iter;
  1.1052 +						pOther = (*iter);
  1.1053 +						if (!pOther->IsLoaded() || pOther == pExt)
  1.1054 +						{
  1.1055 +							continue;
  1.1056 +						}
  1.1057 +						/* Get their dependencies */
  1.1058 +						for (i_iter=pOther->m_Deps.begin();
  1.1059 +							 i_iter!=pOther->m_Deps.end();
  1.1060 +							 i_iter++)
  1.1061 +						{
  1.1062 +							/* Is this dependency to us? */
  1.1063 +							if ((*i_iter).owner != pExt)
  1.1064 +							{
  1.1065 +								continue;
  1.1066 +							}
  1.1067 +							/* Will our dependent care? */
  1.1068 +							if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
  1.1069 +							{
  1.1070 +								g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
  1.1071 +								/* Add to plugin unload list */
  1.1072 +								List<CPlugin *>::iterator p_iter;
  1.1073 +								for (p_iter=pOther->m_Dependents.begin();
  1.1074 +									 p_iter!=pOther->m_Dependents.end();
  1.1075 +									 p_iter++)
  1.1076 +								{
  1.1077 +									if (plugins.find((*p_iter)) == plugins.end())
  1.1078 +									{
  1.1079 +										plugins.push_back((*p_iter));
  1.1080 +									}
  1.1081 +								}
  1.1082 +							}
  1.1083 +						}
  1.1084 +					}
  1.1085 +				}
  1.1086 +				if (pExt->m_Dependents.size())
  1.1087 +				{
  1.1088 +					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
  1.1089 +					List<CPlugin *>::iterator iter;
  1.1090 +					CPlugin *pPlugin;
  1.1091 +					for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
  1.1092 +					{
  1.1093 +						pPlugin = (*iter);
  1.1094 +						if (plugins.find(pPlugin) == plugins.end())
  1.1095 +						{
  1.1096 +							plugins.push_back(pPlugin);
  1.1097 +						}
  1.1098 +					}
  1.1099 +					for (iter = plugins.begin(); iter != plugins.end(); iter++)
  1.1100 +					{
  1.1101 +						pPlugin = (*iter);
  1.1102 +						g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
  1.1103 +					}
  1.1104 +				}
  1.1105 +				srand(static_cast<int>(time(NULL)));
  1.1106 +				pExt->unload_code = (rand() % 877) + 123;	//123 to 999
  1.1107 +				g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
  1.1108 +				g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
  1.1109 +
  1.1110 +				return;
  1.1111 +			}
  1.1112 +		}
  1.1113 +	}
  1.1114 +
  1.1115 +	g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
  1.1116 +	g_RootMenu.DrawGenericOption("info", "Extra extension information");
  1.1117 +	g_RootMenu.DrawGenericOption("list", "List extensions");
  1.1118 +	g_RootMenu.DrawGenericOption("unload", "Unload an extension");
  1.1119 +}
  1.1120 +
  1.1121 +CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
  1.1122 +{
  1.1123 +	if (ptr->type == g_ExtType)
  1.1124 +	{
  1.1125 +		return (CExtension *)(ptr->ptr);
  1.1126 +	}
  1.1127 +
  1.1128 +	return NULL;
  1.1129 +}
  1.1130 +
  1.1131 +CExtensionManager::CExtensionManager()
  1.1132 +{
  1.1133 +}
  1.1134 +
  1.1135 +CExtensionManager::~CExtensionManager()
  1.1136 +{
  1.1137 +}
  1.1138 +
  1.1139 +void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
  1.1140 +{
  1.1141 +	CExtension *pExt = (CExtension *)pSource;
  1.1142 +	pExt->AddLibrary(library);
  1.1143 +	g_PluginSys.OnLibraryAction(library, false, false);
  1.1144 +}
  1.1145 +
  1.1146 +bool CExtensionManager::LibraryExists(const char *library)
  1.1147 +{
  1.1148 +	CExtension *pExt;
  1.1149 +
  1.1150 +	for (List<CExtension *>::iterator iter = m_Libs.begin();
  1.1151 +		 iter != m_Libs.end();
  1.1152 +		 iter++)
  1.1153 +	{
  1.1154 +		pExt = (*iter);
  1.1155 +		for (List<String>::iterator s_iter = pExt->m_Libraries.begin();
  1.1156 +			 s_iter != pExt->m_Libraries.end();
  1.1157 +			 s_iter++)
  1.1158 +		{
  1.1159 +			if ((*s_iter).compare(library) == 0)
  1.1160 +			{
  1.1161 +				return true;
  1.1162 +			}
  1.1163 +		}
  1.1164 +	}
  1.1165 +
  1.1166 +	return false;
  1.1167 +}
  1.1168 +
  1.1169 +IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
  1.1170 +											const char *filepath,
  1.1171 +											const char *filename,
  1.1172 +											char *error,
  1.1173 +											size_t maxlength)
  1.1174 +{
  1.1175 +	IExtension *pAlready;
  1.1176 +	if ((pAlready=FindExtensionByFile(filename)) != NULL)
  1.1177 +	{
  1.1178 +		return pAlready;
  1.1179 +	}
  1.1180 +
  1.1181 +	CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
  1.1182 +
  1.1183 +	if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
  1.1184 +	{
  1.1185 +		pExt->Unload();
  1.1186 +		delete pExt;
  1.1187 +		return NULL;
  1.1188 +	}
  1.1189 +
  1.1190 +	m_Libs.push_back(pExt);
  1.1191 +
  1.1192 +	return pExt;
  1.1193 +}
  1.1194 +
  1.1195 +void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
  1.1196 +{
  1.1197 +	IExtensionInterface *pAPI;
  1.1198 +	List<CExtension *>::iterator iter;
  1.1199 +
  1.1200 +	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  1.1201 +	{
  1.1202 +		if ((pAPI = (*iter)->GetAPI()) == NULL)
  1.1203 +		{
  1.1204 +			continue;
  1.1205 +		}
  1.1206 +		if (pAPI->GetExtensionVersion() > 3)
  1.1207 +		{
  1.1208 +			pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);
  1.1209 +		}
  1.1210 +	}
  1.1211 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/core/ExtensionSys.h	Mon Nov 24 08:39:46 2008 -0600
     2.3 @@ -0,0 +1,186 @@
     2.4 +/**
     2.5 + * vim: set ts=4 :
     2.6 + * =============================================================================
     2.7 + * SourceMod
     2.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     2.9 + * =============================================================================
    2.10 + *
    2.11 + * This program is free software; you can redistribute it and/or modify it under
    2.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    2.13 + * Free Software Foundation.
    2.14 + * 
    2.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    2.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    2.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    2.18 + * details.
    2.19 + *
    2.20 + * You should have received a copy of the GNU General Public License along with
    2.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    2.22 + *
    2.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    2.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    2.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    2.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    2.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    2.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    2.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    2.30 + * or <http://www.sourcemod.net/license.php>.
    2.31 + *
    2.32 + * Version: $Id$
    2.33 + */
    2.34 +
    2.35 +#ifndef _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
    2.36 +#define _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
    2.37 +
    2.38 +#include <IExtensionSys.h>
    2.39 +#include <ILibrarySys.h>
    2.40 +#include <sh_list.h>
    2.41 +#include <sh_string.h>
    2.42 +#include <sm_trie_tpl.h>
    2.43 +#include "sm_globals.h"
    2.44 +#include "ShareSys.h"
    2.45 +#include <ISmmAPI.h>
    2.46 +#include <IPluginSys.h>
    2.47 +#include <IRootConsoleMenu.h>
    2.48 +#include "PluginSys.h"
    2.49 +#include "NativeOwner.h"
    2.50 +
    2.51 +using namespace SourceMod;
    2.52 +using namespace SourceHook;
    2.53 +
    2.54 +class CExtension;
    2.55 +
    2.56 +struct sm_extnative_t
    2.57 +{
    2.58 +	CExtension *owner;
    2.59 +	const sp_nativeinfo_t *info;
    2.60 +};
    2.61 +
    2.62 +class CExtension : 
    2.63 +	public IExtension,
    2.64 +	public CNativeOwner
    2.65 +{
    2.66 +	friend class CExtensionManager;
    2.67 +public:
    2.68 +	virtual ~CExtension();
    2.69 +public: //IExtension
    2.70 +	IExtensionInterface *GetAPI();
    2.71 +	const char *GetFilename();
    2.72 +	IdentityToken_t *GetIdentity();
    2.73 +	ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
    2.74 +	bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
    2.75 +	void FreeDependencyIterator(ITERATOR *iter);
    2.76 +	bool IsRunning(char *error, size_t maxlength);
    2.77 +public:
    2.78 +	void SetError(const char *error);
    2.79 +	void AddDependency(const IfaceInfo *pInfo);
    2.80 +	void AddChildDependent(CExtension *pOther, SMInterface *iface);
    2.81 +	void AddInterface(SMInterface *pInterface);
    2.82 +	void AddPlugin(CPlugin *pPlugin);
    2.83 +	void MarkAllLoaded();
    2.84 +	void AddLibrary(const char *library);
    2.85 +public:
    2.86 +	virtual bool Load(char *error, size_t maxlength);
    2.87 +	virtual bool IsLoaded() =0;
    2.88 +	virtual void Unload() =0;
    2.89 +protected:
    2.90 +	void Initialize(const char *filename, const char *path);
    2.91 +	bool PerformAPICheck(char *error, size_t maxlength);
    2.92 +	void CreateIdentity();
    2.93 +	void DestroyIdentity();
    2.94 +protected:
    2.95 +	IdentityToken_t *m_pIdentToken;
    2.96 +	IExtensionInterface *m_pAPI;
    2.97 +	String m_File;
    2.98 +	String m_Path;
    2.99 +	String m_Error;
   2.100 +	List<IfaceInfo> m_Deps;			/** Dependencies */
   2.101 +	List<IfaceInfo> m_ChildDeps;	/** Children who might depend on us */
   2.102 +	List<SMInterface *> m_Interfaces;
   2.103 +	List<String> m_Libraries;
   2.104 +	unsigned int unload_code;
   2.105 +	bool m_bFullyLoaded;
   2.106 +};
   2.107 +
   2.108 +class CLocalExtension : public CExtension
   2.109 +{
   2.110 +public:
   2.111 +	CLocalExtension(const char *filename);
   2.112 +public:
   2.113 +	bool Load(char *error, size_t maxlength);
   2.114 +	bool IsLoaded();
   2.115 +	void Unload();
   2.116 +	bool IsExternal();
   2.117 +private:
   2.118 +	PluginId m_PlId;
   2.119 +	ILibrary *m_pLib;
   2.120 +};
   2.121 +
   2.122 +class CRemoteExtension : public CExtension
   2.123 +{
   2.124 +public:
   2.125 +	CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path);
   2.126 +public:
   2.127 +	bool Load(char *error, size_t maxlength);
   2.128 +	bool IsLoaded();
   2.129 +	void Unload();
   2.130 +	bool IsExternal();
   2.131 +};
   2.132 +
   2.133 +class CExtensionManager : 
   2.134 +	public IExtensionManager,
   2.135 +	public SMGlobalClass,
   2.136 +	public IPluginsListener,
   2.137 +	public IRootConsoleCommand
   2.138 +{
   2.139 +public:
   2.140 +	CExtensionManager();
   2.141 +	~CExtensionManager();
   2.142 +public: //SMGlobalClass
   2.143 +	void OnSourceModAllInitialized();
   2.144 +	void OnSourceModShutdown();
   2.145 +public: //IExtensionManager
   2.146 +	IExtension *LoadExtension(const char *path, 
   2.147 +		char *error,
   2.148 +		size_t maxlength);
   2.149 +	bool UnloadExtension(IExtension *pExt);
   2.150 +	IExtension *FindExtensionByFile(const char *file);
   2.151 +	IExtension *FindExtensionByName(const char *ext);
   2.152 +	IExtension *LoadExternal(IExtensionInterface *pInterface,
   2.153 +		const char *filepath,
   2.154 +		const char *filename,
   2.155 +		char *error,
   2.156 +		size_t maxlength);
   2.157 +public: //IPluginsListener
   2.158 +	void OnPluginDestroyed(IPlugin *plugin);
   2.159 +public: //IRootConsoleCommand
   2.160 +	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
   2.161 +public:
   2.162 +	IExtension *LoadAutoExtension(const char *path);
   2.163 +	void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
   2.164 +	void AddInterface(IExtension *pOwner, SMInterface *pInterface);
   2.165 +	void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
   2.166 +	void MarkAllLoaded();
   2.167 +	void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
   2.168 +	void TryAutoload();
   2.169 +	void AddLibrary(IExtension *pSource, const char *library);
   2.170 +	bool LibraryExists(const char *library);
   2.171 +	void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
   2.172 +	void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
   2.173 +public:
   2.174 +	CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
   2.175 +	void Shutdown();
   2.176 +	CNativeOwner *GetNativeOwner(IExtension *pExt)
   2.177 +	{
   2.178 +		CExtension *p = (CExtension *)pExt;
   2.179 +		return p;
   2.180 +	}
   2.181 +private:
   2.182 +	CExtension *FindByOrder(unsigned int num);
   2.183 +private:
   2.184 +	List<CExtension *> m_Libs;
   2.185 +};
   2.186 +
   2.187 +extern CExtensionManager g_Extensions;
   2.188 +
   2.189 +#endif //_INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/core/ForwardSys.cpp	Mon Nov 24 08:39:46 2008 -0600
     3.3 @@ -0,0 +1,751 @@
     3.4 +/**
     3.5 + * vim: set ts=4 :
     3.6 + * =============================================================================
     3.7 + * SourceMod
     3.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     3.9 + * =============================================================================
    3.10 + *
    3.11 + * This program is free software; you can redistribute it and/or modify it under
    3.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    3.13 + * Free Software Foundation.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    3.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    3.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    3.18 + * details.
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License along with
    3.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    3.22 + *
    3.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    3.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    3.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    3.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    3.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    3.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    3.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    3.30 + * or <http://www.sourcemod.net/license.php>.
    3.31 + *
    3.32 + * Version: $Id$
    3.33 + */
    3.34 +
    3.35 +#include <assert.h>
    3.36 +#include <stdarg.h>
    3.37 +#include <string.h>
    3.38 +#include "ForwardSys.h"
    3.39 +#include "PluginSys.h"
    3.40 +#include "ShareSys.h"
    3.41 +#include "DebugReporter.h"
    3.42 +
    3.43 +CForwardManager g_Forwards;
    3.44 +
    3.45 +/**
    3.46 + * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
    3.47 + * End of line.  FTL system check.
    3.48 + *
    3.49 + * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
    3.50 + * VARARG FUNCTIONS:
    3.51 + * - Pushing no varargs
    3.52 + */
    3.53 +
    3.54 +// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
    3.55 +// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
    3.56 +
    3.57 +CForwardManager::~CForwardManager()
    3.58 +{
    3.59 +	CStack<CForward *>::iterator iter;
    3.60 +	for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
    3.61 +	{
    3.62 +		delete (*iter);
    3.63 +	}
    3.64 +	m_FreeForwards.popall();
    3.65 +}
    3.66 +
    3.67 +void CForwardManager::OnSourceModAllInitialized()
    3.68 +{
    3.69 +	g_PluginSys.AddPluginsListener(this);
    3.70 +	g_ShareSys.AddInterface(NULL, this);
    3.71 +}
    3.72 +
    3.73 +IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
    3.74 +{
    3.75 +	CForward *fwd;
    3.76 +	va_list ap;
    3.77 +	va_start(ap, types);
    3.78 +	
    3.79 +	fwd = CForward::CreateForward(name, et, num_params, types, ap);
    3.80 +
    3.81 +	va_end(ap);
    3.82 +
    3.83 +	if (fwd)
    3.84 +	{
    3.85 +		g_PluginSys.AddFunctionsToForward(name, fwd);
    3.86 +
    3.87 +		m_managed.push_back(fwd);
    3.88 +	}
    3.89 +
    3.90 +	return fwd;
    3.91 +}
    3.92 +
    3.93 +IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
    3.94 +{
    3.95 +	CForward *fwd;
    3.96 +	va_list ap;
    3.97 +	va_start(ap, types);
    3.98 +
    3.99 +	fwd = CForward::CreateForward(name, et, num_params, types, ap);
   3.100 +
   3.101 +	va_end(ap);
   3.102 +
   3.103 +	if (fwd)
   3.104 +	{
   3.105 +		m_unmanaged.push_back(fwd);
   3.106 +	}
   3.107 +
   3.108 +	return fwd;
   3.109 +}
   3.110 +
   3.111 +void CForwardManager::OnPluginLoaded(IPlugin *plugin)
   3.112 +{
   3.113 +	/* Attach any globally managed forwards */
   3.114 +	List<CForward *>::iterator iter;
   3.115 +	CForward *fwd;
   3.116 +
   3.117 +	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   3.118 +	{
   3.119 +		fwd = (*iter);
   3.120 +		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
   3.121 +		if (pFunc)
   3.122 +		{
   3.123 +			fwd->AddFunction(pFunc);
   3.124 +		}
   3.125 +	}
   3.126 +}
   3.127 +
   3.128 +void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
   3.129 +{
   3.130 +	List<CForward *>::iterator iter;
   3.131 +	CForward *fwd;
   3.132 +
   3.133 +	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   3.134 +	{
   3.135 +		fwd = (*iter);
   3.136 +		fwd->RemoveFunctionsOfPlugin(plugin);
   3.137 +	}
   3.138 +
   3.139 +	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   3.140 +	{
   3.141 +		fwd = (*iter);
   3.142 +		fwd->RemoveFunctionsOfPlugin(plugin);
   3.143 +	}
   3.144 +}
   3.145 +
   3.146 +IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
   3.147 +{
   3.148 +	List<CForward *>::iterator iter;
   3.149 +	CForward *fwd;
   3.150 +
   3.151 +	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
   3.152 +	{
   3.153 +		fwd = (*iter);
   3.154 +		if (strcmp(fwd->GetForwardName(), name) == 0)
   3.155 +		{
   3.156 +			if (ifchng)
   3.157 +			{
   3.158 +				*ifchng = NULL;
   3.159 +			}
   3.160 +			return fwd;
   3.161 +		}
   3.162 +	}
   3.163 +
   3.164 +	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
   3.165 +	{
   3.166 +		fwd = (*iter);
   3.167 +		if (strcmp(fwd->GetForwardName(), name) == 0)
   3.168 +		{
   3.169 +			if (ifchng)
   3.170 +			{
   3.171 +				*ifchng = fwd;
   3.172 +			}
   3.173 +			return fwd;
   3.174 +		}
   3.175 +	}
   3.176 +
   3.177 +	if (ifchng)
   3.178 +	{
   3.179 +		*ifchng = NULL;
   3.180 +	}
   3.181 +
   3.182 +	return NULL;
   3.183 +}
   3.184 +
   3.185 +void CForwardManager::ReleaseForward(IForward *forward)
   3.186 +{
   3.187 +	ForwardFree(static_cast<CForward *>(forward));
   3.188 +}
   3.189 +
   3.190 +void CForwardManager::ForwardFree(CForward *fwd)
   3.191 +{
   3.192 +    if (fwd == NULL)
   3.193 +    {
   3.194 +        return;
   3.195 +    }
   3.196 +
   3.197 +	m_FreeForwards.push(fwd);
   3.198 +	m_managed.remove(fwd);
   3.199 +}
   3.200 +
   3.201 +CForward *CForwardManager::ForwardMake()
   3.202 +{
   3.203 +	CForward *fwd;
   3.204 +	if (m_FreeForwards.empty())
   3.205 +	{
   3.206 +		fwd = new CForward;
   3.207 +	} else {
   3.208 +		fwd = m_FreeForwards.front();
   3.209 +		m_FreeForwards.pop();
   3.210 +	}
   3.211 +	return fwd;
   3.212 +}
   3.213 +
   3.214 +void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
   3.215 +{
   3.216 +	/* No longer used */
   3.217 +}
   3.218 +
   3.219 +/*************************************
   3.220 + * ACTUAL FORWARD API IMPLEMENTATION *
   3.221 + *************************************/
   3.222 +
   3.223 +CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
   3.224 +{
   3.225 +	ParamType _types[SP_MAX_EXEC_PARAMS];
   3.226 +
   3.227 +	if (num_params > SP_MAX_EXEC_PARAMS)
   3.228 +	{
   3.229 +		return NULL;
   3.230 +	}
   3.231 +	
   3.232 +	if (types == NULL && num_params)
   3.233 +	{
   3.234 +		for (unsigned int i=0; i<num_params; i++)
   3.235 +		{
   3.236 +			_types[i] = (ParamType)va_arg(ap, int);
   3.237 +			if (_types[i] == Param_VarArgs && (i != num_params - 1))
   3.238 +			{
   3.239 +				return NULL;
   3.240 +			}
   3.241 +		}
   3.242 +		types = _types;
   3.243 +	} else {
   3.244 +		for (unsigned int i=0; i<num_params; i++)
   3.245 +		{
   3.246 +			_types[i] = types[i];
   3.247 +			if (types[i] == Param_VarArgs && (i != num_params - 1))
   3.248 +			{
   3.249 +				return NULL;
   3.250 +			}
   3.251 +		}
   3.252 +	}
   3.253 +
   3.254 +	/* First parameter can never be varargs */
   3.255 +	if (num_params && _types[0] == Param_VarArgs)
   3.256 +	{
   3.257 +		return NULL;
   3.258 +	}
   3.259 +
   3.260 +	CForward *pForward = g_Forwards.ForwardMake();
   3.261 +	pForward->m_curparam = 0;
   3.262 +	pForward->m_ExecType = et;
   3.263 +	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
   3.264 +	
   3.265 +	for (unsigned int i=0; i<num_params; i++)
   3.266 +	{
   3.267 +		pForward->m_types[i] = _types[i];
   3.268 +	}
   3.269 +
   3.270 +	if (num_params && _types[num_params-1] == Param_VarArgs)
   3.271 +	{
   3.272 +		pForward->m_varargs = num_params--;
   3.273 +	} else {
   3.274 +		pForward->m_varargs = false;
   3.275 +	}
   3.276 +
   3.277 +	pForward->m_numparams = num_params;
   3.278 +	pForward->m_errstate = SP_ERROR_NONE;
   3.279 +
   3.280 +	pForward->m_functions.clear();
   3.281 +
   3.282 +	return pForward;
   3.283 +}
   3.284 +
   3.285 +int CForward::Execute(cell_t *result, IForwardFilter *filter)
   3.286 +{
   3.287 +	if (m_errstate)
   3.288 +	{
   3.289 +		int err = m_errstate;
   3.290 +		Cancel();
   3.291 +		return err;
   3.292 +	}
   3.293 +
   3.294 +	FuncIter iter = m_functions.begin();
   3.295 +	IPluginFunction *func;
   3.296 +	cell_t cur_result = 0;
   3.297 +	cell_t high_result = 0;
   3.298 +	cell_t low_result = 0;
   3.299 +	int err;
   3.300 +	unsigned int failed=0, success=0;
   3.301 +	unsigned int num_params = m_curparam;
   3.302 +	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
   3.303 +	FwdParamInfo *param;
   3.304 +	ParamType type;
   3.305 +
   3.306 +	/* Save local, reset */
   3.307 +	memcpy(temp_info, m_params, sizeof(m_params));
   3.308 +	m_curparam = 0;
   3.309 +
   3.310 +	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   3.311 +	{
   3.312 +		func = (*iter);
   3.313 +
   3.314 +		for (unsigned int i=0; i<num_params; i++)
   3.315 +		{
   3.316 +			int err = SP_ERROR_PARAM;
   3.317 +			param = &temp_info[i];
   3.318 +
   3.319 +			if (i >= m_numparams || m_types[i] == Param_Any)
   3.320 +			{
   3.321 +				type = param->pushedas;
   3.322 +			}
   3.323 +			else
   3.324 +			{
   3.325 +				type = m_types[i];
   3.326 +			}
   3.327 +
   3.328 +			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
   3.329 +			{
   3.330 +				/* If we're byref or we're vararg, we always push everything by ref.
   3.331 +				 * Even if they're byval, we must push them byref.
   3.332 +				 */
   3.333 +				if (type == Param_String)
   3.334 +				{
   3.335 +					err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
   3.336 +				}
   3.337 +				else if (type == Param_Float || type == Param_Cell)
   3.338 +				{
   3.339 +					err = func->PushCellByRef(&param->val); 
   3.340 +				}
   3.341 +				else
   3.342 +				{
   3.343 +					err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
   3.344 +					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
   3.345 +				}
   3.346 +			}
   3.347 +			else
   3.348 +			{
   3.349 +				/* If we're not byref or not vararg, our job is a bit easier. */
   3.350 +				assert(type == Param_Cell || type == Param_Float);
   3.351 +				err = func->PushCell(param->val);
   3.352 +			}
   3.353 +
   3.354 +			if (err != SP_ERROR_NONE)
   3.355 +			{
   3.356 +				g_DbgReporter.GenerateError(func->GetParentContext(), 
   3.357 +					func->GetFunctionID(), 
   3.358 +					err, 
   3.359 +					"Failed to push parameter while executing forward");
   3.360 +				continue;
   3.361 +			}
   3.362 +		}
   3.363 +		
   3.364 +		/* Call the function and deal with the return value. */
   3.365 +		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
   3.366 +		{
   3.367 +			failed++;
   3.368 +		}
   3.369 +		else
   3.370 +		{
   3.371 +			success++;
   3.372 +			switch (m_ExecType)
   3.373 +			{
   3.374 +			case ET_Event:
   3.375 +				{
   3.376 +					if (cur_result > high_result)
   3.377 +					{
   3.378 +						high_result = cur_result;
   3.379 +					}
   3.380 +					break;
   3.381 +				}
   3.382 +			case ET_Hook:
   3.383 +				{
   3.384 +					if (cur_result > high_result)
   3.385 +					{
   3.386 +						high_result = cur_result;
   3.387 +						if ((ResultType)high_result == Pl_Stop)
   3.388 +						{
   3.389 +							goto done;
   3.390 +						}
   3.391 +					}
   3.392 +					break;
   3.393 +				}
   3.394 +			case ET_LowEvent:
   3.395 +				{
   3.396 +					/* Check if the current result is the lowest so far (or if it's the first result) */
   3.397 +					if (cur_result < low_result || success == 1)
   3.398 +					{
   3.399 +						low_result = cur_result;
   3.400 +					}
   3.401 +					break;
   3.402 +				}
   3.403 +			default:
   3.404 +				{
   3.405 +					break;
   3.406 +				}
   3.407 +			}
   3.408 +		}
   3.409 +	}
   3.410 +
   3.411 +done:
   3.412 +
   3.413 +	if (success)
   3.414 +	{
   3.415 +		switch (m_ExecType)
   3.416 +		{
   3.417 +		case ET_Ignore:
   3.418 +			{
   3.419 +				cur_result = 0;
   3.420 +				break;
   3.421 +			}
   3.422 +		case ET_Event:
   3.423 +		case ET_Hook:
   3.424 +			{
   3.425 +				cur_result = high_result;
   3.426 +				break;
   3.427 +			}
   3.428 +		case ET_LowEvent:
   3.429 +			{
   3.430 +				cur_result = low_result;
   3.431 +				break;
   3.432 +			}
   3.433 +		default:
   3.434 +			{
   3.435 +				break;
   3.436 +			}
   3.437 +		}
   3.438 +
   3.439 +		if (result)
   3.440 +		{
   3.441 +			*result = cur_result;
   3.442 +		}
   3.443 +	}
   3.444 +
   3.445 +	return SP_ERROR_NONE;
   3.446 +}
   3.447 +
   3.448 +int CForward::PushCell(cell_t cell)
   3.449 +{
   3.450 +	if (m_curparam < m_numparams)
   3.451 +	{
   3.452 +		if (m_types[m_curparam] == Param_Any)
   3.453 +		{
   3.454 +			m_params[m_curparam].pushedas = Param_Cell;
   3.455 +		} else if (m_types[m_curparam] != Param_Cell) {
   3.456 +			return SetError(SP_ERROR_PARAM);
   3.457 +		}
   3.458 +	} else {
   3.459 +		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   3.460 +		{
   3.461 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.462 +		}
   3.463 +		m_params[m_curparam].pushedas = Param_Cell;
   3.464 +	}
   3.465 +
   3.466 +	m_params[m_curparam++].val = cell;
   3.467 +
   3.468 +	return SP_ERROR_NONE;
   3.469 +}
   3.470 +
   3.471 +int CForward::PushFloat(float number)
   3.472 +{
   3.473 +	if (m_curparam < m_numparams)
   3.474 +	{
   3.475 +		if (m_types[m_curparam] == Param_Any)
   3.476 +		{
   3.477 +			m_params[m_curparam].pushedas = Param_Float;
   3.478 +		} else if (m_types[m_curparam] != Param_Float) {
   3.479 +			return SetError(SP_ERROR_PARAM);
   3.480 +		}
   3.481 +	} else {
   3.482 +		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   3.483 +		{
   3.484 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.485 +		}
   3.486 +		m_params[m_curparam].pushedas = Param_Float;
   3.487 +	}
   3.488 +
   3.489 +	m_params[m_curparam++].val = *(cell_t *)&number;
   3.490 +
   3.491 +	return SP_ERROR_NONE;
   3.492 +}
   3.493 +
   3.494 +int CForward::PushCellByRef(cell_t *cell, int flags)
   3.495 +{
   3.496 +	if (m_curparam < m_numparams)
   3.497 +	{
   3.498 +		if (m_types[m_curparam] == Param_Any)
   3.499 +		{
   3.500 +			m_params[m_curparam].pushedas = Param_CellByRef;
   3.501 +		} else if (m_types[m_curparam] != Param_CellByRef) {
   3.502 +			return SetError(SP_ERROR_PARAM);
   3.503 +		}
   3.504 +	} else {
   3.505 +		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   3.506 +		{
   3.507 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.508 +		}
   3.509 +		m_params[m_curparam].pushedas = Param_CellByRef;
   3.510 +	}
   3.511 +
   3.512 +	_Int_PushArray(cell, 1, flags);
   3.513 +	m_curparam++;
   3.514 +
   3.515 +	return SP_ERROR_NONE;
   3.516 +}
   3.517 +
   3.518 +int CForward::PushFloatByRef(float *num, int flags)
   3.519 +{
   3.520 +	if (m_curparam < m_numparams)
   3.521 +	{
   3.522 +		if (m_types[m_curparam] == Param_Any)
   3.523 +		{
   3.524 +			m_params[m_curparam].pushedas = Param_FloatByRef;
   3.525 +		} else if (m_types[m_curparam] != Param_FloatByRef) {
   3.526 +			return SetError(SP_ERROR_PARAM);
   3.527 +		}
   3.528 +	} else {
   3.529 +		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
   3.530 +		{
   3.531 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.532 +		}
   3.533 +		m_params[m_curparam].pushedas = Param_FloatByRef;
   3.534 +	}
   3.535 +
   3.536 +	_Int_PushArray((cell_t *)num, 1, flags);
   3.537 +	m_curparam++;
   3.538 +
   3.539 +	return SP_ERROR_NONE;
   3.540 +}
   3.541 +
   3.542 +void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
   3.543 +{
   3.544 +	m_params[m_curparam].byref.cells = cells;
   3.545 +	m_params[m_curparam].byref.flags = flags;
   3.546 +	m_params[m_curparam].byref.orig_addr = inarray;
   3.547 +}
   3.548 +
   3.549 +int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
   3.550 +{
   3.551 +	/* We don't allow this here */
   3.552 +	if (!inarray)
   3.553 +	{
   3.554 +		return SetError(SP_ERROR_PARAM);
   3.555 +	}
   3.556 +
   3.557 +	if (m_curparam < m_numparams)
   3.558 +	{
   3.559 +		if (m_types[m_curparam] == Param_Any)
   3.560 +		{
   3.561 +			m_params[m_curparam].pushedas = Param_Array;
   3.562 +		} else if (m_types[m_curparam] != Param_Array) {
   3.563 +			return SetError(SP_ERROR_PARAM);
   3.564 +		}
   3.565 +	} else {
   3.566 +		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   3.567 +		{
   3.568 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.569 +		}
   3.570 +		m_params[m_curparam].pushedas = Param_Array;
   3.571 +	}
   3.572 +
   3.573 +	_Int_PushArray(inarray, cells, flags);
   3.574 +
   3.575 +	m_curparam++;
   3.576 +
   3.577 +	return SP_ERROR_NONE;
   3.578 +}
   3.579 +
   3.580 +void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
   3.581 +{
   3.582 +	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
   3.583 +	m_params[m_curparam].byref.flags = cp_flags;
   3.584 +	m_params[m_curparam].byref.orig_addr = inarray;
   3.585 +	m_params[m_curparam].byref.sz_flags = sz_flags;
   3.586 +}
   3.587 +
   3.588 +int CForward::PushString(const char *string)
   3.589 +{
   3.590 +	if (m_curparam < m_numparams)
   3.591 +	{
   3.592 +		if (m_types[m_curparam] == Param_Any)
   3.593 +		{
   3.594 +			m_params[m_curparam].pushedas = Param_String;
   3.595 +		} else if (m_types[m_curparam] != Param_String) {
   3.596 +			return SetError(SP_ERROR_PARAM);
   3.597 +		}
   3.598 +	} else {
   3.599 +		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   3.600 +		{
   3.601 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.602 +		}
   3.603 +		m_params[m_curparam].pushedas = Param_String;
   3.604 +	}
   3.605 +
   3.606 +	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
   3.607 +	m_curparam++;
   3.608 +
   3.609 +	return SP_ERROR_NONE;
   3.610 +}
   3.611 +
   3.612 +int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
   3.613 +{
   3.614 +	if (m_curparam < m_numparams)
   3.615 +	{
   3.616 +		if (m_types[m_curparam] == Param_Any)
   3.617 +		{
   3.618 +			m_params[m_curparam].pushedas = Param_String;
   3.619 +		} else if (m_types[m_curparam] != Param_String) {
   3.620 +			return SetError(SP_ERROR_PARAM);
   3.621 +		}
   3.622 +	} else {
   3.623 +		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
   3.624 +		{
   3.625 +			return SetError(SP_ERROR_PARAMS_MAX);
   3.626 +		}
   3.627 +		m_params[m_curparam].pushedas = Param_String;
   3.628 +	}
   3.629 +
   3.630 +	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
   3.631 +	m_curparam++;
   3.632 +
   3.633 +	return SP_ERROR_NONE;
   3.634 +}
   3.635 +
   3.636 +void CForward::Cancel()
   3.637 +{
   3.638 +	if (!m_curparam)
   3.639 +	{
   3.640 +		return;
   3.641 +	}
   3.642 +
   3.643 +	m_curparam = 0;
   3.644 +	m_errstate = SP_ERROR_NONE;
   3.645 +}
   3.646 +
   3.647 +bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
   3.648 +{
   3.649 +	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   3.650 +
   3.651 +	if (!pFunc)
   3.652 +	{
   3.653 +		return false;
   3.654 +	}
   3.655 +
   3.656 +	return AddFunction(pFunc);
   3.657 +}
   3.658 +
   3.659 +bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
   3.660 +{
   3.661 +	IPluginFunction *pFunc = pContext->GetFunctionById(index);
   3.662 +
   3.663 +	if (!pFunc)
   3.664 +	{
   3.665 +		return false;
   3.666 +	}
   3.667 +
   3.668 +	return RemoveFunction(pFunc);
   3.669 +}
   3.670 +
   3.671 +bool CForward::RemoveFunction(IPluginFunction *func)
   3.672 +{
   3.673 +	bool found = false;
   3.674 +	FuncIter iter;
   3.675 +	List<IPluginFunction *> *lst;
   3.676 +
   3.677 +	if (func->IsRunnable())
   3.678 +	{
   3.679 +		lst = &m_functions;
   3.680 +	} else {
   3.681 +		lst = &m_paused;
   3.682 +	}
   3.683 +
   3.684 +	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
   3.685 +	{
   3.686 +		if ((*iter) == func)
   3.687 +		{
   3.688 +			found = true;
   3.689 +			lst->erase(iter);
   3.690 +			break;
   3.691 +		}
   3.692 +	}
   3.693 +
   3.694 +	/* Cancel a call, if any */
   3.695 +	if (found || m_curparam)
   3.696 +	{
   3.697 +		func->Cancel();
   3.698 +	}
   3.699 +
   3.700 +	return found;
   3.701 +}
   3.702 +
   3.703 +unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
   3.704 +{
   3.705 +	FuncIter iter;
   3.706 +	IPluginFunction *func;
   3.707 +	unsigned int removed = 0;
   3.708 +	IPluginContext *pContext = plugin->GetBaseContext();
   3.709 +	for (iter=m_functions.begin(); iter!=m_functions.end();)
   3.710 +	{
   3.711 +		func = (*iter);
   3.712 +		if (func->GetParentContext() == pContext)
   3.713 +		{
   3.714 +			iter = m_functions.erase(iter);
   3.715 +			removed++;
   3.716 +		} else {
   3.717 +			iter++;
   3.718 +		}
   3.719 +	}
   3.720 +
   3.721 +	return removed;
   3.722 +}
   3.723 +
   3.724 +bool CForward::AddFunction(IPluginFunction *func)
   3.725 +{
   3.726 +	if (m_curparam)
   3.727 +	{
   3.728 +		return false;
   3.729 +	}
   3.730 +
   3.731 +	if (func->IsRunnable())
   3.732 +	{
   3.733 +		m_functions.push_back(func);
   3.734 +	} else {
   3.735 +		m_paused.push_back(func);
   3.736 +	}
   3.737 +
   3.738 +	return true;
   3.739 +}
   3.740 +
   3.741 +const char *CForward::GetForwardName()
   3.742 +{
   3.743 +	return m_name;
   3.744 +}
   3.745 +
   3.746 +unsigned int CForward::GetFunctionCount()
   3.747 +{
   3.748 +	return m_functions.size();
   3.749 +}
   3.750 +
   3.751 +ExecType CForward::GetExecType()
   3.752 +{
   3.753 +	return m_ExecType;
   3.754 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/core/ForwardSys.h	Mon Nov 24 08:39:46 2008 -0600
     4.3 @@ -0,0 +1,158 @@
     4.4 +/**
     4.5 + * vim: set ts=4 :
     4.6 + * =============================================================================
     4.7 + * SourceMod
     4.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     4.9 + * =============================================================================
    4.10 + *
    4.11 + * This program is free software; you can redistribute it and/or modify it under
    4.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    4.13 + * Free Software Foundation.
    4.14 + * 
    4.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    4.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    4.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    4.18 + * details.
    4.19 + *
    4.20 + * You should have received a copy of the GNU General Public License along with
    4.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    4.22 + *
    4.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    4.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    4.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    4.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    4.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    4.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    4.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    4.30 + * or <http://www.sourcemod.net/license.php>.
    4.31 + *
    4.32 + * Version: $Id$
    4.33 + */
    4.34 +
    4.35 +#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
    4.36 +#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
    4.37 +
    4.38 +#include <IForwardSys.h>
    4.39 +#include <IPluginSys.h>
    4.40 +#include "sm_globals.h"
    4.41 +#include <sh_list.h>
    4.42 +#include <sh_stack.h>
    4.43 +#include "sourcemod.h"
    4.44 +
    4.45 +using namespace SourceHook;
    4.46 +
    4.47 +typedef List<IPluginFunction *>::iterator FuncIter;
    4.48 +
    4.49 +/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
    4.50 +#define FORWARDS_NAME_MAX		64
    4.51 +
    4.52 +struct ByrefInfo
    4.53 +{
    4.54 +	unsigned int cells;
    4.55 +	cell_t *orig_addr;
    4.56 +	int flags;
    4.57 +	int sz_flags;
    4.58 +};
    4.59 +
    4.60 +struct FwdParamInfo
    4.61 +{
    4.62 +	cell_t val;
    4.63 +	ByrefInfo byref;
    4.64 +	ParamType pushedas;
    4.65 +};
    4.66 +
    4.67 +class CForward : public IChangeableForward
    4.68 +{
    4.69 +public: //ICallable
    4.70 +	virtual int PushCell(cell_t cell);
    4.71 +	virtual int PushCellByRef(cell_t *cell, int flags);
    4.72 +	virtual int PushFloat(float number);
    4.73 +	virtual int PushFloatByRef(float *number, int flags);
    4.74 +	virtual int PushArray(cell_t *inarray, unsigned int cells, int flags);
    4.75 +	virtual int PushString(const char *string);
    4.76 +	virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
    4.77 +	virtual void Cancel();
    4.78 +public: //IForward
    4.79 +	virtual const char *GetForwardName();
    4.80 +	virtual unsigned int GetFunctionCount();
    4.81 +	virtual ExecType GetExecType();
    4.82 +	virtual int Execute(cell_t *result, IForwardFilter *filter);
    4.83 +public: //IChangeableForward
    4.84 +	virtual bool RemoveFunction(IPluginFunction *func);
    4.85 +	virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
    4.86 +	virtual bool AddFunction(IPluginFunction *func);
    4.87 +	virtual bool AddFunction(IPluginContext *ctx, funcid_t index);
    4.88 +	virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
    4.89 +public:
    4.90 +	static CForward *CreateForward(const char *name, 
    4.91 +								   ExecType et, 
    4.92 +								   unsigned int num_params, 
    4.93 +								   const ParamType *types, 
    4.94 +								   va_list ap);
    4.95 +private:
    4.96 +	void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
    4.97 +	void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
    4.98 +	inline int SetError(int err)
    4.99 +	{
   4.100 +		m_errstate = err;
   4.101 +		return err;
   4.102 +	}
   4.103 +protected:
   4.104 +	/* :TODO: I want a caching list type here.
   4.105 +	 * Destroying these things and using new/delete for their members feels bad.
   4.106 +	 */
   4.107 +	mutable List<IPluginFunction *> m_functions;
   4.108 +	mutable List<IPluginFunction *> m_paused;
   4.109 +
   4.110 +	/* Type and name information */
   4.111 +	FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
   4.112 +	ParamType m_types[SP_MAX_EXEC_PARAMS];
   4.113 +	char m_name[FORWARDS_NAME_MAX+1];
   4.114 +	unsigned int m_numparams;
   4.115 +	unsigned int m_varargs;
   4.116 +	ExecType m_ExecType;
   4.117 +
   4.118 +	/* State information */
   4.119 +	unsigned int m_curparam;
   4.120 +	int m_errstate;
   4.121 +};
   4.122 +
   4.123 +class CForwardManager : 
   4.124 +	public IForwardManager,
   4.125 +	public IPluginsListener,
   4.126 +	public SMGlobalClass
   4.127 +{
   4.128 +	friend class CForward;
   4.129 +public:
   4.130 +	~CForwardManager();
   4.131 +public: //IForwardManager
   4.132 +	IForward *CreateForward(const char *name, 
   4.133 +		ExecType et, 
   4.134 +		unsigned int num_params, 
   4.135 +		const ParamType *types, 
   4.136 +		...);
   4.137 +	IChangeableForward *CreateForwardEx(const char *name, 
   4.138 +		ExecType et, 
   4.139 +		int num_params, 
   4.140 +		const ParamType *types, 
   4.141 +		...);
   4.142 +	IForward *FindForward(const char *name, IChangeableForward **ifchng);
   4.143 +	void ReleaseForward(IForward *forward);
   4.144 +public: //IPluginsListener
   4.145 +	void OnPluginLoaded(IPlugin *plugin);
   4.146 +	void OnPluginUnloaded(IPlugin *plugin);
   4.147 +	void OnPluginPauseChange(IPlugin *plugin, bool paused);
   4.148 +public: //SMGlobalClass
   4.149 +	void OnSourceModAllInitialized();
   4.150 +protected:
   4.151 +	CForward *ForwardMake();
   4.152 +	void ForwardFree(CForward *fwd);
   4.153 +private:
   4.154 +	CStack<CForward *> m_FreeForwards;
   4.155 +	List<CForward *> m_managed;
   4.156 +	List<CForward *> m_unmanaged;
   4.157 +};
   4.158 +
   4.159 +extern CForwardManager g_Forwards;
   4.160 +
   4.161 +#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/core/HandleSys.cpp	Mon Nov 24 08:39:46 2008 -0600
     5.3 @@ -0,0 +1,1076 @@
     5.4 +/**
     5.5 + * vim: set ts=4 :
     5.6 + * =============================================================================
     5.7 + * SourceMod
     5.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     5.9 + * =============================================================================
    5.10 + *
    5.11 + * This program is free software; you can redistribute it and/or modify it under
    5.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    5.13 + * Free Software Foundation.
    5.14 + * 
    5.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    5.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    5.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    5.18 + * details.
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License along with
    5.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    5.22 + *
    5.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    5.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    5.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    5.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    5.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    5.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    5.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    5.30 + * or <http://www.sourcemod.net/license.php>.
    5.31 + *
    5.32 + * Version: $Id$
    5.33 + */
    5.34 +
    5.35 +#include "HandleSys.h"
    5.36 +#include "ShareSys.h"
    5.37 +#include "PluginSys.h"
    5.38 +#include "ExtensionSys.h"
    5.39 +#include "Logger.h"
    5.40 +#include <assert.h>
    5.41 +#include <string.h>
    5.42 +#include "sm_stringutil.h"
    5.43 +
    5.44 +HandleSystem g_HandleSys;
    5.45 +
    5.46 +QHandle *ignore_handle;
    5.47 +
    5.48 +inline HandleType_t TypeParent(HandleType_t type)
    5.49 +{
    5.50 +	return (type & ~HANDLESYS_SUBTYPE_MASK);
    5.51 +}
    5.52 +
    5.53 +inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
    5.54 +{
    5.55 +	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
    5.56 +}
    5.57 +
    5.58 +HandleSystem::HandleSystem()
    5.59 +{
    5.60 +	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
    5.61 +	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
    5.62 +
    5.63 +	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
    5.64 +	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
    5.65 +
    5.66 +	m_TypeLookup = sm_trie_create();
    5.67 +	m_strtab = new BaseStringTable(512);
    5.68 +
    5.69 +	m_TypeTail = 0;
    5.70 +}
    5.71 +
    5.72 +HandleSystem::~HandleSystem()
    5.73 +{
    5.74 +	delete [] m_Handles;
    5.75 +	delete [] m_Types;
    5.76 +	sm_trie_destroy(m_TypeLookup);
    5.77 +	delete m_strtab;
    5.78 +}
    5.79 +
    5.80 +
    5.81 +HandleType_t HandleSystem::CreateType(const char *name, 
    5.82 +									  IHandleTypeDispatch *dispatch, 
    5.83 +									  HandleType_t parent, 
    5.84 +									  const TypeAccess *typeAccess, 
    5.85 +									  const HandleAccess *hndlAccess, 
    5.86 +									  IdentityToken_t *ident,
    5.87 +									  HandleError *err)
    5.88 +{
    5.89 +	if (!dispatch)
    5.90 +	{
    5.91 +		if (err)
    5.92 +		{
    5.93 +			*err = HandleError_Parameter;
    5.94 +		}
    5.95 +		return 0;
    5.96 +	}
    5.97 +
    5.98 +	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
    5.99 +	{
   5.100 +		if (err)
   5.101 +		{
   5.102 +			*err = HandleError_Version;
   5.103 +		}
   5.104 +		return 0;
   5.105 +	}
   5.106 +
   5.107 +	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   5.108 +	{
   5.109 +		if (err)
   5.110 +		{
   5.111 +			*err = HandleError_Version;
   5.112 +		}
   5.113 +		return 0;
   5.114 +	}
   5.115 +
   5.116 +	bool isChild = false;
   5.117 +
   5.118 +	if (parent != 0)
   5.119 +	{
   5.120 +		isChild = true;
   5.121 +		if (parent & HANDLESYS_SUBTYPE_MASK)
   5.122 +		{
   5.123 +			if (err)
   5.124 +			{
   5.125 +				*err = HandleError_NoInherit;
   5.126 +			}
   5.127 +			return 0;
   5.128 +		}
   5.129 +		if (parent >= HANDLESYS_TYPEARRAY_SIZE
   5.130 +			|| m_Types[parent].dispatch == NULL)
   5.131 +		{
   5.132 +			if (err)
   5.133 +			{
   5.134 +				*err = HandleError_Parameter;
   5.135 +			}
   5.136 +			return 0;
   5.137 +		}
   5.138 +		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
   5.139 +			&& (m_Types[parent].typeSec.ident != ident))
   5.140 +		{
   5.141 +			if (err)
   5.142 +			{
   5.143 +				*err = HandleError_Access;
   5.144 +			}
   5.145 +			return 0;
   5.146 +		}
   5.147 +	}
   5.148 +
   5.149 +	if (name && name[0] != '\0')
   5.150 +	{
   5.151 +		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
   5.152 +		{
   5.153 +			if (err)
   5.154 +			{
   5.155 +				*err = HandleError_Parameter;
   5.156 +			}
   5.157 +			return 0;
   5.158 +		}
   5.159 +	}
   5.160 +
   5.161 +	unsigned int index;
   5.162 +
   5.163 +	if (isChild)
   5.164 +	{
   5.165 +		QHandleType *pParent = &m_Types[parent];
   5.166 +		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
   5.167 +		{
   5.168 +			if (err)
   5.169 +			{
   5.170 +				*err = HandleError_Limit;
   5.171 +			}
   5.172 +			return 0;
   5.173 +		}
   5.174 +		index = 0;
   5.175 +		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   5.176 +		{
   5.177 +			if (m_Types[parent + i].dispatch == NULL)
   5.178 +			{
   5.179 +				index = parent + i;
   5.180 +				break;
   5.181 +			}
   5.182 +		}
   5.183 +		if (!index)
   5.184 +		{
   5.185 +			if (err)
   5.186 +			{
   5.187 +				*err = HandleError_Limit;
   5.188 +			}
   5.189 +			return 0;
   5.190 +		}
   5.191 +		pParent->children++;
   5.192 +	} else {
   5.193 +		if (m_FreeTypes == 0)
   5.194 +		{
   5.195 +			/* Reserve another index */
   5.196 +			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
   5.197 +			{
   5.198 +				if (err)
   5.199 +				{
   5.200 +					*err = HandleError_Limit;
   5.201 +				}
   5.202 +				return 0;
   5.203 +			} else {
   5.204 +				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
   5.205 +				index = m_TypeTail;
   5.206 +			}
   5.207 +		} else {
   5.208 +			/* The "free array" is compacted into the normal array for easiness */
   5.209 +			index = m_Types[m_FreeTypes--].freeID;
   5.210 +		}
   5.211 +	}
   5.212 +
   5.213 +	QHandleType *pType = &m_Types[index];
   5.214 +	
   5.215 +	pType->dispatch = dispatch;
   5.216 +	if (name && name[0] != '\0')
   5.217 +	{
   5.218 +		pType->nameIdx = m_strtab->AddString(name);
   5.219 +		sm_trie_insert(m_TypeLookup, name, (void *)pType);
   5.220 +	} else {
   5.221 +		pType->nameIdx = -1;
   5.222 +	}
   5.223 +
   5.224 +	pType->opened = 0;
   5.225 +
   5.226 +	if (typeAccess)
   5.227 +	{
   5.228 +		pType->typeSec = *typeAccess;
   5.229 +	} else {
   5.230 +		InitAccessDefaults(&pType->typeSec, NULL);
   5.231 +		pType->typeSec.ident = ident;
   5.232 +	}
   5.233 +
   5.234 +	if (hndlAccess)
   5.235 +	{
   5.236 +		pType->hndlSec = *hndlAccess;
   5.237 +	} else {
   5.238 +		InitAccessDefaults(NULL, &pType->hndlSec);
   5.239 +	}
   5.240 +
   5.241 +	if (!isChild)
   5.242 +	{
   5.243 +		pType->children = 0;
   5.244 +	}
   5.245 +
   5.246 +	return index;
   5.247 +}
   5.248 +
   5.249 +bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
   5.250 +{
   5.251 +	QHandleType *_type;
   5.252 +
   5.253 +	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
   5.254 +	{
   5.255 +		return false;
   5.256 +	}
   5.257 +
   5.258 +	unsigned int offset = _type - m_Types;
   5.259 +
   5.260 +	if (type)
   5.261 +	{
   5.262 +		*type = offset;
   5.263 +	}
   5.264 +
   5.265 +	return true;
   5.266 +}
   5.267 +
   5.268 +HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
   5.269 +{
   5.270 +	if (m_FreeHandles == 0)
   5.271 +	{
   5.272 +		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
   5.273 +		{
   5.274 +			return HandleError_Limit;;
   5.275 +		}
   5.276 +		*handle = ++m_HandleTail;
   5.277 +	}
   5.278 +	else
   5.279 +	{
   5.280 +		*handle = m_Handles[m_FreeHandles--].freeID;
   5.281 +	}
   5.282 +
   5.283 +	return HandleError_None;
   5.284 +}
   5.285 +
   5.286 +HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
   5.287 +						   QHandle **in_pHandle, 
   5.288 +						   unsigned int *in_index, 
   5.289 +						   Handle_t *in_handle,
   5.290 +						   IdentityToken_t *owner,
   5.291 +						   bool identity)
   5.292 +{
   5.293 +	HandleError err;
   5.294 +	unsigned int owner_index = 0;
   5.295 +
   5.296 +	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
   5.297 +	{
   5.298 +		return HandleError_Identity;
   5.299 +	}
   5.300 +
   5.301 +	unsigned int handle;
   5.302 +	if ((err = TryAllocHandle(&handle)) != HandleError_None)
   5.303 +	{
   5.304 +		if (!TryAndFreeSomeHandles()
   5.305 +			|| (err = TryAllocHandle(&handle)) != HandleError_None)
   5.306 +		{
   5.307 +			return err;
   5.308 +		}
   5.309 +	}
   5.310 +
   5.311 +	QHandle *pHandle = &m_Handles[handle];
   5.312 +	
   5.313 +	assert(pHandle->set == false);
   5.314 +
   5.315 +	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
   5.316 +	{
   5.317 +		m_HSerial = 1;
   5.318 +	}
   5.319 +
   5.320 +	/* Set essential information */
   5.321 +	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
   5.322 +	pHandle->refcount = 1;
   5.323 +	pHandle->type = type;
   5.324 +	pHandle->serial = m_HSerial;
   5.325 +	pHandle->owner = owner;
   5.326 +	pHandle->ch_next = 0;
   5.327 +	pHandle->access_special = false;
   5.328 +	pHandle->is_destroying = false;
   5.329 +
   5.330 +	/* Create the hash value */
   5.331 +	Handle_t hash = pHandle->serial;
   5.332 +	hash <<= 16;
   5.333 +	hash |= handle;
   5.334 +
   5.335 +	/* Add a reference count to the type */
   5.336 +	m_Types[type].opened++;
   5.337 +
   5.338 +	/* Output */
   5.339 +	*in_pHandle = pHandle;
   5.340 +	*in_index = handle;
   5.341 +	*in_handle = hash;
   5.342 +
   5.343 +	/* Decode the identity token 
   5.344 +	 * For now, we don't allow nested ownership
   5.345 +	 */
   5.346 +	if (owner && !identity)
   5.347 +	{
   5.348 +		QHandle *pIdentity = &m_Handles[owner_index];
   5.349 +		if (pIdentity->ch_prev == 0)
   5.350 +		{
   5.351 +			pIdentity->ch_prev = handle;
   5.352 +			pIdentity->ch_next = handle;
   5.353 +			pHandle->ch_prev = 0;
   5.354 +		}
   5.355 +		else
   5.356 +		{
   5.357 +			/* Link previous node to us (forward) */
   5.358 +			m_Handles[pIdentity->ch_next].ch_next = handle;
   5.359 +			/* Link us to previous node (backwards) */
   5.360 +			pHandle->ch_prev = pIdentity->ch_next;
   5.361 +			/* Set new tail */
   5.362 +			pIdentity->ch_next = handle;
   5.363 +		}
   5.364 +		pIdentity->refcount++;
   5.365 +	}
   5.366 +	else
   5.367 +	{
   5.368 +		pHandle->ch_prev = 0;
   5.369 +	}
   5.370 +
   5.371 +	return HandleError_None;
   5.372 +}
   5.373 +
   5.374 +void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
   5.375 +{
   5.376 +	if (!type
   5.377 +		|| type >= HANDLESYS_TYPEARRAY_SIZE
   5.378 +		|| m_Types[type].dispatch == NULL)
   5.379 +	{
   5.380 +		return;
   5.381 +	}
   5.382 +
   5.383 +	m_Types[type].typeSec.ident = pToken;
   5.384 +}
   5.385 +
   5.386 +Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
   5.387 +									   void *object, 
   5.388 +									   const HandleSecurity *pSec,
   5.389 +									   HandleError *err, 
   5.390 +									   const HandleAccess *pAccess,
   5.391 +									   bool identity)
   5.392 +{
   5.393 +	IdentityToken_t *ident;
   5.394 +	IdentityToken_t *owner;
   5.395 +
   5.396 +	if (pSec)
   5.397 +	{
   5.398 +		ident = pSec->pIdentity;
   5.399 +		owner = pSec->pOwner;
   5.400 +	} else {
   5.401 +		ident = NULL;
   5.402 +		owner = NULL;
   5.403 +	}
   5.404 +
   5.405 +	if (!type 
   5.406 +		|| type >= HANDLESYS_TYPEARRAY_SIZE
   5.407 +		|| m_Types[type].dispatch == NULL)
   5.408 +	{
   5.409 +		if (err)
   5.410 +		{
   5.411 +			*err = HandleError_Parameter;
   5.412 +		}
   5.413 +		return 0;
   5.414 +	}
   5.415 +
   5.416 +	/* Check to see if we're allowed to create this handle type */
   5.417 +	QHandleType *pType = &m_Types[type];
   5.418 +	if (!pType->typeSec.access[HTypeAccess_Create]
   5.419 +	&& (!pType->typeSec.ident
   5.420 +		|| pType->typeSec.ident != ident))
   5.421 +	{
   5.422 +		if (err)
   5.423 +		{
   5.424 +			*err = HandleError_Access;
   5.425 +		}
   5.426 +		return 0;
   5.427 +	}
   5.428 +
   5.429 +	unsigned int index;
   5.430 +	Handle_t handle;
   5.431 +	QHandle *pHandle;
   5.432 +	HandleError _err;
   5.433 +
   5.434 +	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
   5.435 +	{
   5.436 +		if (err)
   5.437 +		{
   5.438 +			*err = _err;
   5.439 +		}
   5.440 +		return 0;
   5.441 +	}
   5.442 +
   5.443 +	if (pAccess)
   5.444 +	{
   5.445 +		pHandle->access_special = true;
   5.446 +		pHandle->sec = *pAccess;
   5.447 +	}
   5.448 +
   5.449 +	pHandle->object = object;
   5.450 +	pHandle->clone = 0;
   5.451 +
   5.452 +	return handle;
   5.453 +}
   5.454 +
   5.455 +Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
   5.456 +{
   5.457 +	return CreateHandleInt(type, object, pSec, err, pAccess, false);
   5.458 +}
   5.459 +
   5.460 +Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
   5.461 +{
   5.462 +	HandleSecurity sec;
   5.463 +
   5.464 +	sec.pIdentity = ident;
   5.465 +	sec.pOwner = owner;
   5.466 +
   5.467 +	return CreateHandleEx(type, object, &sec, NULL, err);
   5.468 +}
   5.469 +
   5.470 +bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
   5.471 +{
   5.472 +	/* Check the type inheritance */
   5.473 +	if (intype & HANDLESYS_SUBTYPE_MASK)
   5.474 +	{
   5.475 +		if (intype != outtype
   5.476 +			&& (TypeParent(intype) != TypeParent(outtype)))
   5.477 +		{
   5.478 +			return false;
   5.479 +		}
   5.480 +	} else {
   5.481 +		if (intype != outtype)
   5.482 +		{
   5.483 +			return false;
   5.484 +		}
   5.485 +	}
   5.486 +
   5.487 +	return true;
   5.488 +}
   5.489 +
   5.490 +HandleError HandleSystem::GetHandle(Handle_t handle,
   5.491 +									IdentityToken_t *ident, 
   5.492 +									QHandle **in_pHandle, 
   5.493 +									unsigned int *in_index,
   5.494 +									bool ignoreFree)
   5.495 +{
   5.496 +	unsigned int serial = (handle >> 16);
   5.497 +	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
   5.498 +
   5.499 +	if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
   5.500 +	{
   5.501 +		return HandleError_Index;
   5.502 +	}
   5.503 +
   5.504 +	QHandle *pHandle = &m_Handles[index];
   5.505 +
   5.506 +	if (!pHandle->set
   5.507 +		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
   5.508 +	{
   5.509 +		return HandleError_Freed;
   5.510 +	} else if (pHandle->set == HandleSet_Identity
   5.511 +			   && ident != g_ShareSys.GetIdentRoot())
   5.512 +	{
   5.513 +		/* Only IdentityHandle() can read this! */
   5.514 +		return HandleError_Identity;
   5.515 +	}
   5.516 +	if (pHandle->serial != serial)
   5.517 +	{
   5.518 +		return HandleError_Changed;
   5.519 +	}
   5.520 +
   5.521 +	*in_pHandle = pHandle;
   5.522 +	*in_index = index;
   5.523 +
   5.524 +	return HandleError_None;
   5.525 +}
   5.526 +
   5.527 +bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
   5.528 +{
   5.529 +	QHandleType *pType = &m_Types[pHandle->type];
   5.530 +	unsigned int access;
   5.531 +
   5.532 +	if (pHandle->access_special)
   5.533 +	{
   5.534 +		access = pHandle->sec.access[right];
   5.535 +	} else {
   5.536 +		access = pType->hndlSec.access[right];
   5.537 +	}
   5.538 +
   5.539 +	/* Check if the type's identity matches */
   5.540 +	if (access & HANDLE_RESTRICT_IDENTITY)
   5.541 +	{
   5.542 +		IdentityToken_t *owner = pType->typeSec.ident;
   5.543 +		if (!owner
   5.544 +			|| (!pSecurity || pSecurity->pIdentity != owner))
   5.545 +		{
   5.546 +			return false;
   5.547 +		}
   5.548 +	}
   5.549 +
   5.550 +	/* Check if the owner is allowed */
   5.551 +	if (access & HANDLE_RESTRICT_OWNER)
   5.552 +	{
   5.553 +		IdentityToken_t *owner = pHandle->owner;
   5.554 +		if (owner
   5.555 +			&& (!pSecurity || pSecurity->pOwner != owner))
   5.556 +		{
   5.557 +			return false;
   5.558 +		}
   5.559 +	}
   5.560 +
   5.561 +	return true;
   5.562 +}
   5.563 +
   5.564 +HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
   5.565 +{
   5.566 +	/* Get a new Handle ID */
   5.567 +	unsigned int new_index;
   5.568 +	QHandle *pNewHandle;
   5.569 +	Handle_t new_handle;
   5.570 +	HandleError err;
   5.571 +
   5.572 +	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
   5.573 +	{
   5.574 +		return err;
   5.575 +	}
   5.576 +
   5.577 +	/* Assign permissions from parent */
   5.578 +	if (pHandle->access_special)
   5.579 +	{
   5.580 +		pNewHandle->access_special = true;
   5.581 +		pNewHandle->sec = pHandle->sec;
   5.582 +	}
   5.583 +
   5.584 +	pNewHandle->clone = index;
   5.585 +	pHandle->refcount++;
   5.586 +
   5.587 +	*newhandle = new_handle;
   5.588 +
   5.589 +	return HandleError_None;
   5.590 +}
   5.591 +
   5.592 +HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
   5.593 +{
   5.594 +	HandleError err;
   5.595 +	QHandle *pHandle;
   5.596 +	unsigned int index;
   5.597 +	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   5.598 +
   5.599 +	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   5.600 +	{
   5.601 +		return err;
   5.602 +	}
   5.603 +
   5.604 +	/* Identities cannot be cloned */
   5.605 +	if (pHandle->set == HandleSet_Identity)
   5.606 +	{
   5.607 +		return HandleError_Identity;
   5.608 +	}
   5.609 +
   5.610 +	/* Check if the handle can be cloned */
   5.611 +	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
   5.612 +	{
   5.613 +		return HandleError_Access;
   5.614 +	}
   5.615 +
   5.616 +	/* Make sure we're not cloning a clone */
   5.617 +	if (pHandle->clone)
   5.618 +	{
   5.619 +		QHandle *pParent = &m_Handles[pHandle->clone];
   5.620 +		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
   5.621 +	}
   5.622 +
   5.623 +	return CloneHandle(pHandle, index, newhandle, newOwner);
   5.624 +}
   5.625 +
   5.626 +HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
   5.627 +{
   5.628 +	QHandleType *pType = &m_Types[pHandle->type];
   5.629 +
   5.630 +	if (pHandle->clone)
   5.631 +	{
   5.632 +		/* If we're a clone, decrease the parent reference count */
   5.633 +		QHandle *pMaster;
   5.634 +		unsigned int master;
   5.635 +
   5.636 +		/* Note that if we ever have per-handle security, we would need to re-check
   5.637 +		* the access on this Handle. */
   5.638 +		master = pHandle->clone;
   5.639 +		pMaster = &m_Handles[master];
   5.640 +
   5.641 +		/* Release the clone now */
   5.642 +		ReleasePrimHandle(index);
   5.643 +
   5.644 +		/* Decrement the master's reference count */
   5.645 +		if (--pMaster->refcount == 0)
   5.646 +		{
   5.647 +			/* Type should be the same but do this anyway... */
   5.648 +			pType = &m_Types[pMaster->type];
   5.649 +			pMaster->is_destroying = true;
   5.650 +			pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
   5.651 +			ReleasePrimHandle(master);
   5.652 +		}
   5.653 +	} else if (pHandle->set == HandleSet_Identity) {
   5.654 +		/* If we're an identity, skip all this stuff!
   5.655 +		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
   5.656 +		 */
   5.657 +		ReleasePrimHandle(index);
   5.658 +	} else {
   5.659 +		/* Decrement, free if necessary */
   5.660 +		if (--pHandle->refcount == 0)
   5.661 +		{
   5.662 +			pHandle->is_destroying = true;
   5.663 +			pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
   5.664 +			ReleasePrimHandle(index);
   5.665 +		} else {
   5.666 +			/* We must be cloned, so mark ourselves as freed */
   5.667 +			pHandle->set = HandleSet_Freed;
   5.668 +			/* Now, unlink us, so we're not being tracked by the owner */
   5.669 +			if (pHandle->owner)
   5.670 +			{
   5.671 +				UnlinkHandleFromOwner(pHandle, index);
   5.672 +			}
   5.673 +		}
   5.674 +	}
   5.675 +
   5.676 +	return HandleError_None;
   5.677 +}
   5.678 +
   5.679 +HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
   5.680 +{
   5.681 +	unsigned int index;
   5.682 +	QHandle *pHandle;
   5.683 +	HandleError err;
   5.684 +	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   5.685 +
   5.686 +	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   5.687 +	{
   5.688 +		return err;
   5.689 +	}
   5.690 +
   5.691 +	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
   5.692 +	{
   5.693 +		return HandleError_Access;
   5.694 +	}
   5.695 +
   5.696 +	if (pHandle->is_destroying)
   5.697 +	{
   5.698 +		/* Someone tried to free this recursively.  
   5.699 +		 * We'll just ignore this safely.
   5.700 +		 */
   5.701 +		return HandleError_None;
   5.702 +	}
   5.703 +
   5.704 +	return FreeHandle(pHandle, index);
   5.705 +}
   5.706 +
   5.707 +HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
   5.708 +{
   5.709 +	unsigned int index;
   5.710 +	QHandle *pHandle;
   5.711 +	HandleError err;
   5.712 +	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
   5.713 +
   5.714 +	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
   5.715 +	{
   5.716 +		return err;
   5.717 +	}
   5.718 +
   5.719 +	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
   5.720 +	{
   5.721 +		return HandleError_Access;
   5.722 +	}
   5.723 +
   5.724 +	/* Check the type inheritance */
   5.725 +	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
   5.726 +	{
   5.727 +		if (pHandle->type != type
   5.728 +			&& (TypeParent(pHandle->type) != TypeParent(type)))
   5.729 +		{
   5.730 +			return HandleError_Type;
   5.731 +		}
   5.732 +	} else if (type) {
   5.733 +		if (pHandle->type != type)
   5.734 +		{
   5.735 +			return HandleError_Type;
   5.736 +		}
   5.737 +	}
   5.738 +
   5.739 +	if (object)
   5.740 +	{
   5.741 +		/* if we're a clone, the rules change - object is ONLY in our reference */
   5.742 +		if (pHandle->clone)
   5.743 +		{
   5.744 +			pHandle = &m_Handles[pHandle->clone];
   5.745 +		}
   5.746 +		*object = pHandle->object;
   5.747 +	}
   5.748 +
   5.749 +	return HandleError_None;
   5.750 +}
   5.751 +
   5.752 +void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
   5.753 +{
   5.754 +	/* Unlink us if necessary */
   5.755 +	unsigned int ident_index;
   5.756 +	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
   5.757 +	{
   5.758 +		/* Uh-oh! */
   5.759 +		assert(pHandle->owner == 0);
   5.760 +		return;
   5.761 +	}
   5.762 +	/* Note that since 0 is an invalid handle, if any of these links are 0,
   5.763 +	* the data can still be set.
   5.764 +	*/
   5.765 +	QHandle *pIdentity = &m_Handles[ident_index];
   5.766 +
   5.767 +	/* Unlink case: We're the head AND tail node */
   5.768 +	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
   5.769 +	{
   5.770 +		pIdentity->ch_prev = 0;
   5.771 +		pIdentity->ch_next = 0;
   5.772 +	}
   5.773 +	/* Unlink case: We're the head node */
   5.774 +	else if (index == pIdentity->ch_prev) {
   5.775 +		/* Link us to the next in the chain */
   5.776 +		pIdentity->ch_prev = pHandle->ch_next;
   5.777 +		/* Patch up the previous link */
   5.778 +		m_Handles[pHandle->ch_next].ch_prev = 0;
   5.779 +	}
   5.780 +	/* Unlink case: We're the tail node */
   5.781 +	else if (index == pIdentity->ch_next) {
   5.782 +		/* Link us to the previous in the chain */
   5.783 +		pIdentity->ch_next = pHandle->ch_prev;
   5.784 +		/* Patch up the next link */
   5.785 +		m_Handles[pHandle->ch_prev].ch_next = 0;
   5.786 +	}
   5.787 +	/* Unlink case: We're in the middle! */
   5.788 +	else {
   5.789 +		/* Patch the forward reference */
   5.790 +		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
   5.791 +		/* Patch the backward reference */
   5.792 +		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
   5.793 +	}
   5.794 +
   5.795 +	/* Lastly, decrease the reference count */
   5.796 +	pIdentity->refcount--;
   5.797 +}
   5.798 +
   5.799 +void HandleSystem::ReleasePrimHandle(unsigned int index)
   5.800 +{
   5.801 +	QHandle *pHandle = &m_Handles[index];
   5.802 +	HandleSet set = pHandle->set;
   5.803 +
   5.804 +	if (pHandle->owner && (set != HandleSet_Identity))
   5.805 +	{
   5.806 +		UnlinkHandleFromOwner(pHandle, index);
   5.807 +	}
   5.808 +
   5.809 +	/* Were we an identity ourself? */
   5.810 +	QHandle *pLocal;
   5.811 +	if (set == HandleSet_Identity)
   5.812 +	{
   5.813 +		/* Extra work to do.  We need to find everything connected to this identity and release it. */
   5.814 +		unsigned int ch_index;
   5.815 +#if defined _DEBUG
   5.816 +		unsigned int old_index = 0;
   5.817 +#endif
   5.818 +		while ((ch_index = pHandle->ch_next) != 0)
   5.819 +		{
   5.820 +			pLocal = &m_Handles[ch_index];
   5.821 +#if defined _DEBUG
   5.822 +			assert(old_index != ch_index);
   5.823 +			assert(pLocal->set == HandleSet_Used);
   5.824 +			old_index = ch_index;
   5.825 +#endif
   5.826 +			FreeHandle(pLocal, ch_index);
   5.827 +		}
   5.828 +	}
   5.829 +
   5.830 +	pHandle->set = HandleSet_None;
   5.831 +	m_Types[pHandle->type].opened--;
   5.832 +	m_Handles[++m_FreeHandles].freeID = index;
   5.833 +}
   5.834 +
   5.835 +bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
   5.836 +{
   5.837 +	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
   5.838 +	{
   5.839 +		return false;
   5.840 +	}
   5.841 +
   5.842 +	QHandleType *pType = &m_Types[type];
   5.843 +
   5.844 +	if (pType->typeSec.ident
   5.845 +		&& pType->typeSec.ident != ident)
   5.846 +	{
   5.847 +		return false;
   5.848 +	}
   5.849 +
   5.850 +	if (pType->dispatch == NULL)
   5.851 +	{
   5.852 +		return false;
   5.853 +	}
   5.854 +
   5.855 +	/* Remove children if we have to */
   5.856 +	if (!(type & HANDLESYS_SUBTYPE_MASK))
   5.857 +	{
   5.858 +		QHandleType *childType;
   5.859 +		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
   5.860 +		{
   5.861 +			childType = &m_Types[type + i];
   5.862 +			if (childType->dispatch)
   5.863 +			{
   5.864 +				RemoveType(type + i, childType->typeSec.ident);
   5.865 +			}
   5.866 +		}
   5.867 +		/* Link us into the free chain */
   5.868 +		m_Types[++m_FreeTypes].freeID = type;
   5.869 +	}
   5.870 +
   5.871 +	/* Invalidate the type now */
   5.872 +	IHandleTypeDispatch *dispatch = pType->dispatch;
   5.873 +	pType->dispatch = NULL;
   5.874 +
   5.875 +	/* Make sure nothing is using this type. */
   5.876 +	if (pType->opened)
   5.877 +	{
   5.878 +		QHandle *pHandle;
   5.879 +		for (unsigned int i=1; i<=m_HandleTail; i++)
   5.880 +		{
   5.881 +			pHandle = &m_Handles[i];
   5.882 +			if (!pHandle->set || pHandle->type != type)
   5.883 +			{
   5.884 +				continue;
   5.885 +			}
   5.886 +			if (pHandle->clone)
   5.887 +			{
   5.888 +				/* Get parent */
   5.889 +				QHandle *pOther = &m_Handles[pHandle->clone];
   5.890 +				if (--pOther->refcount == 0)
   5.891 +				{
   5.892 +					/* Free! */
   5.893 +					dispatch->OnHandleDestroy(type, pOther->object);
   5.894 +					ReleasePrimHandle(pHandle->clone);
   5.895 +				}
   5.896 +				/* Unlink ourselves since we don't have a reference count */
   5.897 +				ReleasePrimHandle(i);
   5.898 +			} else {
   5.899 +				/* If it's not a clone, we still have to check the reference count.
   5.900 +				 * Either way, we'll be destroyed eventually because the handle types do not change.
   5.901 +				 */
   5.902 +				if (--pHandle->refcount == 0)
   5.903 +				{
   5.904 +					/* Free! */
   5.905 +					dispatch->OnHandleDestroy(type, pHandle->object);
   5.906 +					ReleasePrimHandle(i);
   5.907 +				}
   5.908 +			}
   5.909 +			if (pType->opened == 0)
   5.910 +			{
   5.911 +				break;
   5.912 +			}
   5.913 +		}
   5.914 +	}
   5.915 +
   5.916 +	/* Remove it from the type cache. */
   5.917 +	if (pType->nameIdx != -1)
   5.918 +	{
   5.919 +		const char *typeName;
   5.920 +
   5.921 +		typeName = m_strtab->GetString(pType->nameIdx);
   5.922 +		sm_trie_delete(m_TypeLookup, typeName);
   5.923 +	}
   5.924 +
   5.925 +	return true;
   5.926 +}
   5.927 +
   5.928 +bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
   5.929 +{
   5.930 +	if (pTypeAccess)
   5.931 +	{
   5.932 +		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   5.933 +		{
   5.934 +			return false;
   5.935 +		}
   5.936 +		pTypeAccess->access[HTypeAccess_Create] = false;
   5.937 +		pTypeAccess->access[HTypeAccess_Inherit] = false;
   5.938 +		pTypeAccess->ident = NULL;
   5.939 +	}
   5.940 +
   5.941 +	if (pHandleAccess)
   5.942 +	{
   5.943 +		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   5.944 +		{
   5.945 +			return false;
   5.946 +		}
   5.947 +
   5.948 +		pHandleAccess->access[HandleAccess_Clone] = 0;
   5.949 +		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
   5.950 +		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
   5.951 +	}
   5.952 +
   5.953 +	return true;
   5.954 +}
   5.955 +
   5.956 +bool HandleSystem::TryAndFreeSomeHandles()
   5.957 +{
   5.958 +	IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
   5.959 +	IPlugin *highest_owner = NULL;
   5.960 +	unsigned int highest_handle_count = 0;
   5.961 +
   5.962 +	/* Search all plugins */
   5.963 +	while (pl_iter->MorePlugins())
   5.964 +	{
   5.965 +		IPlugin *plugin = pl_iter->GetPlugin();
   5.966 +		IdentityToken_t *identity = plugin->GetIdentity();
   5.967 +		unsigned int handle_count = 0;
   5.968 +
   5.969 +		if (identity == NULL)
   5.970 +		{
   5.971 +			continue;
   5.972 +		}
   5.973 +
   5.974 +		/* Search all handles */
   5.975 +		for (unsigned int i = 1; i <= m_HandleTail; i++)
   5.976 +		{
   5.977 +			if (m_Handles[i].set != HandleSet_Used)
   5.978 +			{
   5.979 +				continue;
   5.980 +			}
   5.981 +			if (m_Handles[i].owner == identity)
   5.982 +			{
   5.983 +				handle_count++;
   5.984 +			}
   5.985 +		}
   5.986 +
   5.987 +		if (handle_count > highest_handle_count)
   5.988 +		{
   5.989 +			highest_owner = plugin;
   5.990 +			highest_handle_count = handle_count;
   5.991 +		}
   5.992 +
   5.993 +		pl_iter->NextPlugin();
   5.994 +	}
   5.995 +
   5.996 +	if (highest_owner == NULL || highest_handle_count == 0)
   5.997 +	{
   5.998 +		return false;
   5.999 +	}
  5.1000 +
  5.1001 +	g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
  5.1002 +	g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
  5.1003 +	g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
  5.1004 +
  5.1005 +	highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
  5.1006 +
  5.1007 +	return g_PluginSys.UnloadPlugin(highest_owner);
  5.1008 +}
  5.1009 +
  5.1010 +void HandleSystem::Dump(HANDLE_REPORTER rep)
  5.1011 +{
  5.1012 +	unsigned int total_size = 0;
  5.1013 +	rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
  5.1014 +	rep("--------------------------------------------------------------------------");
  5.1015 +	for (unsigned int i = 1; i <= m_HandleTail; i++)
  5.1016 +	{
  5.1017 +		if (m_Handles[i].set != HandleSet_Used)
  5.1018 +		{
  5.1019 +			continue;
  5.1020 +		}
  5.1021 +		/* Get the index */
  5.1022 +		unsigned int index = (m_Handles[i].serial << 16) | i;
  5.1023 +		/* Determine the owner */
  5.1024 +		const char *owner = "UNKNOWN";
  5.1025 +		if (m_Handles[i].owner)
  5.1026 +		{
  5.1027 +			IdentityToken_t *pOwner = m_Handles[i].owner;
  5.1028 +			if (pOwner == g_pCoreIdent)
  5.1029 +			{
  5.1030 +				owner = "CORE";
  5.1031 +			}
  5.1032 +			else if (pOwner == g_PluginSys.GetIdentity())
  5.1033 +			{
  5.1034 +				owner = "PLUGINSYS";
  5.1035 +			}
  5.1036 +			else
  5.1037 +			{
  5.1038 +				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
  5.1039 +				if (ext)
  5.1040 +				{
  5.1041 +					owner = ext->GetFilename();
  5.1042 +				}
  5.1043 +				else
  5.1044 +				{
  5.1045 +					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
  5.1046 +					if (pPlugin)
  5.1047 +					{
  5.1048 +						owner = pPlugin->GetFilename();
  5.1049 +					}
  5.1050 +				}
  5.1051 +			}
  5.1052 +		}
  5.1053 +		else
  5.1054 +		{
  5.1055 +			owner = "NONE";
  5.1056 +		}
  5.1057 +		const char *type = "ANON";
  5.1058 +		QHandleType *pType = &m_Types[m_Handles[i].type];
  5.1059 +		unsigned int size = 0;
  5.1060 +		if (pType->nameIdx != -1)
  5.1061 +		{
  5.1062 +			type = m_strtab->GetString(pType->nameIdx);
  5.1063 +		}
  5.1064 +		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
  5.1065 +			|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
  5.1066 +		{
  5.1067 +			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
  5.1068 +		}
  5.1069 +		else
  5.1070 +		{
  5.1071 +			char buffer[32];
  5.1072 +			UTIL_Format(buffer, sizeof(buffer), "%d", size);
  5.1073 +			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
  5.1074 +			total_size += size;
  5.1075 +		}
  5.1076 +	}
  5.1077 +	rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
  5.1078 +}
  5.1079 +
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/core/HandleSys.h	Mon Nov 24 08:39:46 2008 -0600
     6.3 @@ -0,0 +1,225 @@
     6.4 +/**
     6.5 + * vim: set ts=4 :
     6.6 + * =============================================================================
     6.7 + * SourceMod
     6.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6.9 + * =============================================================================
    6.10 + *
    6.11 + * This program is free software; you can redistribute it and/or modify it under
    6.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    6.13 + * Free Software Foundation.
    6.14 + * 
    6.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    6.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    6.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    6.18 + * details.
    6.19 + *
    6.20 + * You should have received a copy of the GNU General Public License along with
    6.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    6.22 + *
    6.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    6.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    6.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    6.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    6.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    6.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    6.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    6.30 + * or <http://www.sourcemod.net/license.php>.
    6.31 + *
    6.32 + * Version: $Id$
    6.33 + */
    6.34 +
    6.35 +#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
    6.36 +#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
    6.37 +
    6.38 +#include <IHandleSys.h>
    6.39 +#include <stdio.h>
    6.40 +#include "sm_globals.h"
    6.41 +#include "sm_trie.h"
    6.42 +#include "sourcemod.h"
    6.43 +#include "sm_memtable.h"
    6.44 +
    6.45 +#define HANDLESYS_MAX_HANDLES		(1<<14)
    6.46 +#define HANDLESYS_MAX_TYPES			(1<<9)
    6.47 +#define HANDLESYS_MAX_SUBTYPES		0xF
    6.48 +#define HANDLESYS_SUBTYPE_MASK		0xF
    6.49 +#define HANDLESYS_TYPEARRAY_SIZE	(HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
    6.50 +#define HANDLESYS_MAX_SERIALS		0xFFFF
    6.51 +#define HANDLESYS_SERIAL_MASK		0xFFFF0000
    6.52 +#define HANDLESYS_HANDLE_MASK		0x0000FFFF
    6.53 +
    6.54 +#define HANDLESYS_MEMUSAGE_MIN_VERSION		3
    6.55 +
    6.56 +/**
    6.57 + *   The QHandle is a nasty structure that compacts the handle system into a big vector.
    6.58 + * The members of the vector each encapsulate one Handle, however, they also act as nodes
    6.59 + * in an inlined linked list and an inlined vector.
    6.60 + *
    6.61 + *   The first of these lists is the 'freeID' list.  Each node from 1 to N (where N
    6.62 + * is the number of free nodes) has a 'freeID' that specifies a free Handle ID.  This
    6.63 + * is a quick hack to get around allocating a second base vector.
    6.64 + *
    6.65 + *   The second vector is the identity linked list.  An identity has its own handle, so
    6.66 + * these handles are used as sentinel nodes for index linking.  They point to the first and last
    6.67 + * index into the handle array.  Each subsequent Handle who is owned by that identity is mapped into
    6.68 + * that list.  This lets owning identities be unloaded in O(n) time.
    6.69 + *
    6.70 + *   Eventually, there may be a third list for type chains.
    6.71 + */
    6.72 +
    6.73 +enum HandleSet
    6.74 +{
    6.75 +	HandleSet_None = 0,
    6.76 +	HandleSet_Used,			/* The Handle is in use */
    6.77 +	HandleSet_Freed,		/* The "master" Handle of a clone chain is freed */
    6.78 +	HandleSet_Identity,		/* The Handle is a special identity */
    6.79 +};
    6.80 +
    6.81 +struct QHandle
    6.82 +{
    6.83 +	HandleType_t type;			/* Handle type */
    6.84 +	void *object;				/* Unmaintained object pointer */
    6.85 +	IdentityToken_t *owner;		/* Identity of object which owns this */
    6.86 +	unsigned int serial;		/* Serial no. for sanity checking */
    6.87 +	unsigned int refcount;		/* Reference count for safe destruction */
    6.88 +	unsigned int clone;			/* If non-zero, this is our cloned parent index */
    6.89 +	HandleSet set;				/* Information about the handle's state */
    6.90 +	bool access_special;		/* Whether or not access rules are special or type-derived */
    6.91 +	bool is_destroying;			/* Whether or not the handle is being destroyed */
    6.92 +	HandleAccess sec;			/* Security rules */
    6.93 +	/* The following variables are unrelated to the Handle array, and used 
    6.94 +	 * as an inlined chain of information */
    6.95 +	unsigned int freeID;		/* ID of a free handle in the free handle chain */
    6.96 +	/* Indexes into the handle array for owner membership.
    6.97 +	 * For identity roots, these are treated as the head/tail. */
    6.98 +	unsigned int ch_prev;		/* chained previous handle */
    6.99 +	unsigned int ch_next;		/* chained next handle */
   6.100 +};
   6.101 +
   6.102 +struct QHandleType
   6.103 +{
   6.104 +	IHandleTypeDispatch *dispatch;
   6.105 +	unsigned int freeID;
   6.106 +	unsigned int children;
   6.107 +	TypeAccess typeSec;
   6.108 +	HandleAccess hndlSec;
   6.109 +	unsigned int opened;
   6.110 +	int nameIdx;
   6.111 +};
   6.112 +
   6.113 +typedef void (HANDLE_REPORTER)(const char *str, ...);
   6.114 +
   6.115 +class HandleSystem : 
   6.116 +	public IHandleSys
   6.117 +{
   6.118 +	friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
   6.119 +	friend class ShareSystem;
   6.120 +public:
   6.121 +	HandleSystem();
   6.122 +	~HandleSystem();
   6.123 +public: //IHandleSystem
   6.124 +
   6.125 +	HandleType_t CreateType(const char *name,
   6.126 +		IHandleTypeDispatch *dispatch,
   6.127 +		HandleType_t parent,
   6.128 +		const TypeAccess *typeAccess,
   6.129 +		const HandleAccess *hndlAccess,
   6.130 +		IdentityToken_t *ident,
   6.131 +		HandleError *err);
   6.132 +
   6.133 +	bool RemoveType(HandleType_t type, IdentityToken_t *ident);
   6.134 +
   6.135 +	bool FindHandleType(const char *name, HandleType_t *type);
   6.136 +
   6.137 +	Handle_t CreateHandle(HandleType_t type, 
   6.138 +		void *object,
   6.139 +		IdentityToken_t *owner,
   6.140 +		IdentityToken_t *ident,
   6.141 +		HandleError *err);
   6.142 +
   6.143 +	HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
   6.144 +
   6.145 +	HandleError CloneHandle(Handle_t handle, 
   6.146 +		Handle_t *newhandle, 
   6.147 +		IdentityToken_t *newOwner,
   6.148 +		const HandleSecurity *pSecurity);
   6.149 +
   6.150 +	HandleError ReadHandle(Handle_t handle, 
   6.151 +		HandleType_t type, 
   6.152 +		const HandleSecurity *pSecurity,
   6.153 +		void **object);
   6.154 +
   6.155 +	bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
   6.156 +
   6.157 +	bool TypeCheck(HandleType_t intype, HandleType_t outtype);
   6.158 +
   6.159 +	virtual Handle_t CreateHandleEx(HandleType_t type, 
   6.160 +		void *object,
   6.161 +		const HandleSecurity *pSec,
   6.162 +		const HandleAccess *pAccess,
   6.163 +		HandleError *err);
   6.164 +
   6.165 +	void Dump(HANDLE_REPORTER rep);
   6.166 +protected:
   6.167 +	/**
   6.168 +	 * Decodes a handle with sanity and security checking.
   6.169 +	 */
   6.170 +	HandleError GetHandle(Handle_t handle, 
   6.171 +						  IdentityToken_t *ident, 
   6.172 +						  QHandle **pHandle, 
   6.173 +						  unsigned int *index,
   6.174 +						  bool ignoreFree=false);
   6.175 +
   6.176 +	/**
   6.177 +	 * Creates a basic handle and sets its reference count to 1.
   6.178 +	 * Does not do any type or security checking.
   6.179 +	 */
   6.180 +	HandleError MakePrimHandle(HandleType_t type, 
   6.181 +							   QHandle **pHandle, 
   6.182 +							   unsigned int *index, 
   6.183 +							   HandleType_t *handle,
   6.184 +							   IdentityToken_t *owner,
   6.185 +							   bool identity=false);
   6.186 +
   6.187 +	/**
   6.188 +	 * Frees a primitive handle.  Does no object freeing, only reference count, bookkeeping, 
   6.189 +	 * and linked list maintenance.
   6.190 +	 * If used on an Identity handle, destroys all Handles under that identity.
   6.191 +	 */
   6.192 +	void ReleasePrimHandle(unsigned int index);
   6.193 +
   6.194 +	/**
   6.195 +	 * Sets the security owner of a type.
   6.196 +	 */
   6.197 +	void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
   6.198 +
   6.199 +	/**
   6.200 +	 * Helper function to check access rights.
   6.201 +	 */
   6.202 +	bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
   6.203 +
   6.204 +	/** 
   6.205 +	 * Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
   6.206 +	 */
   6.207 +	HandleError FreeHandle(QHandle *pHandle, unsigned int index);
   6.208 +	void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
   6.209 +	HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
   6.210 +	Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
   6.211 +
   6.212 +	bool TryAndFreeSomeHandles();
   6.213 +	HandleError TryAllocHandle(unsigned int *handle);
   6.214 +private:
   6.215 +	QHandle *m_Handles;
   6.216 +	QHandleType *m_Types;
   6.217 +	Trie *m_TypeLookup;
   6.218 +	unsigned int m_TypeTail;
   6.219 +	unsigned int m_FreeTypes;
   6.220 +	unsigned int m_HandleTail;
   6.221 +	unsigned int m_FreeHandles;
   6.222 +	unsigned int m_HSerial;
   6.223 +	BaseStringTable *m_strtab;
   6.224 +};
   6.225 +
   6.226 +extern HandleSystem g_HandleSys;
   6.227 +
   6.228 +#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/core/LibrarySys.cpp	Mon Nov 24 08:39:46 2008 -0600
     7.3 @@ -0,0 +1,441 @@
     7.4 +/**
     7.5 + * vim: set ts=4 :
     7.6 + * =============================================================================
     7.7 + * SourceMod
     7.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     7.9 + * =============================================================================
    7.10 + *
    7.11 + * This program is free software; you can redistribute it and/or modify it under
    7.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    7.13 + * Free Software Foundation.
    7.14 + * 
    7.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    7.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    7.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    7.18 + * details.
    7.19 + *
    7.20 + * You should have received a copy of the GNU General Public License along with
    7.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    7.22 + *
    7.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    7.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    7.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    7.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    7.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    7.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    7.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    7.30 + * or <http://www.sourcemod.net/license.php>.
    7.31 + *
    7.32 + * Version: $Id$
    7.33 + */
    7.34 +
    7.35 +#include <sys/stat.h>
    7.36 +#include <stdio.h>
    7.37 +#include <stdarg.h>
    7.38 +#include <string.h>
    7.39 +#include <sm_platform.h>
    7.40 +#include "sm_stringutil.h"
    7.41 +#include "LibrarySys.h"
    7.42 +
    7.43 +LibrarySystem g_LibSys;
    7.44 +
    7.45 +CLibrary::~CLibrary()
    7.46 +{
    7.47 +	if (m_lib)
    7.48 +	{
    7.49 +#if defined PLATFORM_WINDOWS
    7.50 +		FreeLibrary(m_lib);
    7.51 +#elif defined PLATFORM_POSIX
    7.52 +		dlclose(m_lib);
    7.53 +#endif
    7.54 +		m_lib = NULL;
    7.55 +	}
    7.56 +}
    7.57 +
    7.58 +CLibrary::CLibrary(LibraryHandle me)
    7.59 +{
    7.60 +	m_lib = me;
    7.61 +}
    7.62 +
    7.63 +void CLibrary::CloseLibrary()
    7.64 +{
    7.65 +	delete this;
    7.66 +}
    7.67 +
    7.68 +void *CLibrary::GetSymbolAddress(const char *symname)
    7.69 +{
    7.70 +#if defined PLATFORM_WINDOWS
    7.71 +	return GetProcAddress(m_lib, symname);
    7.72 +#elif defined PLATFORM_POSIX
    7.73 +	return dlsym(m_lib, symname);
    7.74 +#endif
    7.75 +}
    7.76 +
    7.77 +
    7.78 +/********************
    7.79 + ** Directory Code **
    7.80 + ********************/
    7.81 +
    7.82 +
    7.83 +CDirectory::CDirectory(const char *path)
    7.84 +{
    7.85 +#if defined PLATFORM_WINDOWS
    7.86 +	char newpath[PLATFORM_MAX_PATH];
    7.87 +	snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
    7.88 +	m_dir = FindFirstFileA(newpath, &m_fd);
    7.89 +	if (!IsValid())
    7.90 +	{
    7.91 +		m_fd.cFileName[0] = '\0';
    7.92 +	}
    7.93 +#elif defined PLATFORM_POSIX
    7.94 +	m_dir = opendir(path);
    7.95 +	if (IsValid())
    7.96 +	{
    7.97 +		/* :TODO: we need to read past "." and ".."! */
    7.98 +		ep = readdir(m_dir);
    7.99 +		snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
   7.100 +	} else {
   7.101 +		ep = NULL;
   7.102 +	}
   7.103 +#endif
   7.104 +}
   7.105 +
   7.106 +CDirectory::~CDirectory()
   7.107 +{
   7.108 +	if (IsValid())
   7.109 +	{
   7.110 +#if defined PLATFORM_WINDOWS
   7.111 +		FindClose(m_dir);
   7.112 +#elif defined PLATFORM_POSIX
   7.113 +		closedir(m_dir);
   7.114 +#endif
   7.115 +	}
   7.116 +}
   7.117 +
   7.118 +void CDirectory::NextEntry()
   7.119 +{
   7.120 +#if defined PLATFORM_WINDOWS
   7.121 +	if (FindNextFile(m_dir, &m_fd) == 0)
   7.122 +	{
   7.123 +		FindClose(m_dir);
   7.124 +		m_dir = INVALID_HANDLE_VALUE;
   7.125 +	}
   7.126 +#elif defined PLATFORM_POSIX
   7.127 +	if ((ep=readdir(m_dir)) == NULL)
   7.128 +	{
   7.129 +		closedir(m_dir);
   7.130 +		m_dir = NULL;
   7.131 +	}
   7.132 +#endif
   7.133 +}
   7.134 +
   7.135 +bool CDirectory::IsEntryValid()
   7.136 +{
   7.137 +	return IsValid();
   7.138 +}
   7.139 +
   7.140 +bool CDirectory::IsEntryDirectory()
   7.141 +{
   7.142 +#if defined PLATFORM_WINDOWS
   7.143 +	return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
   7.144 +#elif defined PLATFORM_LINUX
   7.145 +	char temppath[PLATFORM_MAX_PATH];
   7.146 +	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
   7.147 +	return g_LibSys.IsPathDirectory(temppath);
   7.148 +#endif
   7.149 +}
   7.150 +
   7.151 +bool CDirectory::IsEntryFile()
   7.152 +{
   7.153 +#if defined PLATFORM_WINDOWS
   7.154 +	return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
   7.155 +#elif defined PLATFORM_POSIX
   7.156 +	char temppath[PLATFORM_MAX_PATH];
   7.157 +	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
   7.158 +	return g_LibSys.IsPathFile(temppath);
   7.159 +#endif
   7.160 +}
   7.161 +
   7.162 +const char *CDirectory::GetEntryName()
   7.163 +{
   7.164 +#if defined PLATFORM_WINDOWS
   7.165 +	return m_fd.cFileName;
   7.166 +#elif defined PLATFORM_LINUX
   7.167 +	return ep ? ep->d_name : "";
   7.168 +#endif
   7.169 +}
   7.170 +
   7.171 +bool CDirectory::MoreFiles()
   7.172 +{
   7.173 +	return IsValid();
   7.174 +}
   7.175 +
   7.176 +bool CDirectory::IsValid()
   7.177 +{
   7.178 +#if defined PLATFORM_WINDOWS
   7.179 +	return (m_dir != INVALID_HANDLE_VALUE);
   7.180 +#elif defined PLATFORM_LINUX
   7.181 +	return (m_dir != NULL);
   7.182 +#endif
   7.183 +}
   7.184 +
   7.185 +
   7.186 +/*************************
   7.187 + ** Library System Code **
   7.188 + *************************/
   7.189 +
   7.190 +
   7.191 +bool LibrarySystem::PathExists(const char *path)
   7.192 +{
   7.193 +#if defined PLATFORM_WINDOWS
   7.194 +	DWORD attr = GetFileAttributesA(path);
   7.195 +
   7.196 +	return (attr != INVALID_FILE_ATTRIBUTES);
   7.197 +#elif defined PLATFORM_POSIX
   7.198 +	struct stat s;
   7.199 +
   7.200 +	return (stat(path, &s) == 0);
   7.201 +#endif
   7.202 +}
   7.203 +
   7.204 +bool LibrarySystem::IsPathFile(const char *path)
   7.205 +{
   7.206 +#if defined PLATFORM_WINDOWS
   7.207 +	DWORD attr = GetFileAttributes(path);
   7.208 +
   7.209 +	if (attr == INVALID_FILE_ATTRIBUTES)
   7.210 +	{
   7.211 +		return false;
   7.212 +	}
   7.213 +
   7.214 +	if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
   7.215 +	{
   7.216 +		return false;
   7.217 +	}
   7.218 +
   7.219 +	return true;
   7.220 +#elif defined PLATFORM_LINUX
   7.221 +	struct stat s;
   7.222 +
   7.223 +	if (stat(path, &s) != 0)
   7.224 +	{
   7.225 +		return false;
   7.226 +	}
   7.227 +
   7.228 +	return S_ISREG(s.st_mode) ? true : false;
   7.229 +#endif
   7.230 +}
   7.231 +
   7.232 +bool LibrarySystem::IsPathDirectory(const char *path)
   7.233 +{
   7.234 +#if defined PLATFORM_WINDOWS
   7.235 +	DWORD attr = GetFileAttributes(path);
   7.236 +
   7.237 +	if (attr == INVALID_FILE_ATTRIBUTES)
   7.238 +	{
   7.239 +		return false;
   7.240 +	}
   7.241 +
   7.242 +	if (attr & FILE_ATTRIBUTE_DIRECTORY)
   7.243 +	{
   7.244 +		return true;
   7.245 +	}
   7.246 +
   7.247 +#elif defined PLATFORM_LINUX
   7.248 +	struct stat s;
   7.249 +
   7.250 +	if (stat(path, &s) != 0)
   7.251 +	{
   7.252 +		return false;
   7.253 +	}
   7.254 +
   7.255 +	if (S_ISDIR(s.st_mode))
   7.256 +	{
   7.257 +		return true;
   7.258 +	}
   7.259 +#endif
   7.260 +
   7.261 +	return false;
   7.262 +}
   7.263 +
   7.264 +IDirectory *LibrarySystem::OpenDirectory(const char *path)
   7.265 +{
   7.266 +	CDirectory *dir = new CDirectory(path);
   7.267 +
   7.268 +	if (!dir->IsValid())
   7.269 +	{
   7.270 +		delete dir;
   7.271 +		return NULL;
   7.272 +	}
   7.273 +
   7.274 +	return dir;
   7.275 +}
   7.276 +
   7.277 +void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
   7.278 +{
   7.279 +	if (error && maxlength)
   7.280 +	{
   7.281 +#if defined PLATFORM_WINDOWS
   7.282 +		DWORD dw = GetLastError();
   7.283 +		FormatMessageA(
   7.284 +			FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   7.285 +			NULL,
   7.286 +			dw,
   7.287 +			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   7.288 +			(LPSTR)error,
   7.289 +			maxlength,
   7.290 +			NULL);
   7.291 +#elif defined PLATFORM_POSIX
   7.292 +		UTIL_Format(error, maxlength, "%s", strerror(errno));
   7.293 +#endif
   7.294 +	}
   7.295 +}
   7.296 +
   7.297 +void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
   7.298 +{
   7.299 +#if defined PLATFORM_WINDOWS
   7.300 +	GetPlatformError(buffer, maxlength);
   7.301 +#elif defined PLATFORM_POSIX
   7.302 +	if (buffer != NULL && maxlength)
   7.303 +	{
   7.304 +		strncopy(buffer, dlerror(), maxlength);
   7.305 +	}
   7.306 +#endif
   7.307 +}
   7.308 +
   7.309 +void LibrarySystem::CloseDirectory(IDirectory *dir)
   7.310 +{
   7.311 +	delete dir;
   7.312 +}
   7.313 +
   7.314 +ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
   7.315 +{
   7.316 +	LibraryHandle lib;
   7.317 +#if defined PLATFORM_WINDOWS
   7.318 +	lib = LoadLibraryA(path);
   7.319 +#elif defined PLATFORM_POSIX
   7.320 +	lib = dlopen(path, RTLD_NOW);
   7.321 +#endif
   7.322 +
   7.323 +	if (lib == NULL)
   7.324 +	{
   7.325 +		GetLoaderError(error, maxlength);
   7.326 +		return NULL;
   7.327 +	}
   7.328 +
   7.329 +	return new CLibrary(lib);
   7.330 +}
   7.331 +
   7.332 +size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
   7.333 +{
   7.334 +	va_list ap;
   7.335 +	va_start(ap, fmt);
   7.336 +	size_t mylen = vsnprintf(buffer, len, fmt, ap);
   7.337 +	va_end(ap);
   7.338 +
   7.339 +	if (mylen >= len)
   7.340 +	{
   7.341 +		mylen = len - 1;
   7.342 +		buffer[mylen] = '\0';
   7.343 +	}
   7.344 +
   7.345 +	for (size_t i=0; i<mylen; i++)
   7.346 +	{
   7.347 +		if (buffer[i] == PLATFORM_SEP_ALTCHAR)
   7.348 +		{
   7.349 +			buffer[i] = PLATFORM_SEP_CHAR;
   7.350 +		}
   7.351 +	}
   7.352 +
   7.353 +	return mylen;
   7.354 +}
   7.355 +
   7.356 +const char *LibrarySystem::GetFileExtension(const char *filename)
   7.357 +{
   7.358 +	size_t len, end;
   7.359 +
   7.360 +	len = strlen(filename);
   7.361 +
   7.362 +	/* Minimum string length for filename with ext would be 3; example: a.a */
   7.363 +	if (len < 3)
   7.364 +	{
   7.365 +		return NULL;
   7.366 +	}
   7.367 +
   7.368 +	end = len - 1;
   7.369 +
   7.370 +	for (size_t i = end; i <= end; i--)
   7.371 +	{
   7.372 +		if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
   7.373 +		{
   7.374 +			break;
   7.375 +		}
   7.376 +
   7.377 +		if (filename[i] == '.' && i != end && i != 0)
   7.378 +		{
   7.379 +			return &filename[++i];
   7.380 +		}
   7.381 +	}
   7.382 +
   7.383 +	return NULL;
   7.384 +}
   7.385 +
   7.386 +bool LibrarySystem::CreateFolder(const char *path)
   7.387 +{
   7.388 +#if defined PLATFORM_WINDOWS
   7.389 +	return (mkdir(path) != -1);
   7.390 +#elif defined PLATFORM_POSIX
   7.391 +	return (mkdir(path, 0775) != -1);
   7.392 +#endif
   7.393 +}
   7.394 +
   7.395 +size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path)
   7.396 +{
   7.397 +	size_t length = strlen(path);
   7.398 +
   7.399 +	for (size_t i = length - 1;
   7.400 +		 i >= 0 && i <= length - 1;
   7.401 +		 i--)
   7.402 +	{
   7.403 +		if (path[i] == '/' 
   7.404 +#if defined PLATFORM_WINDOWS
   7.405 +			|| path[i] == '\\'
   7.406 +#endif
   7.407 +			)
   7.408 +		{
   7.409 +			return UTIL_Format(buffer, maxlength, "%s", &path[i+1]);
   7.410 +		}
   7.411 +	}
   7.412 +
   7.413 +	/* We scanned and found no path separator */
   7.414 +	return UTIL_Format(buffer, maxlength, "%s", path);
   7.415 +}
   7.416 +
   7.417 +bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)
   7.418 +{
   7.419 +#ifdef PLATFORM_WINDOWS
   7.420 +	struct _stat s;
   7.421 +	if (_stat(path, &s) != 0)
   7.422 +#elif defined PLATFORM_POSIX
   7.423 +	struct stat s;
   7.424 +	if (stat(path, &s) != 0)
   7.425 +#endif
   7.426 +	{
   7.427 +		return false;
   7.428 +	}
   7.429 +
   7.430 +	if (type == FileTime_LastAccess)
   7.431 +	{
   7.432 +		*pTime = s.st_atime;
   7.433 +	}
   7.434 +	else if (type == FileTime_Created)
   7.435 +	{
   7.436 +		*pTime = s.st_ctime;
   7.437 +	}
   7.438 +	else if (type == FileTime_LastChange)
   7.439 +	{
   7.440 +		*pTime = s.st_mtime;
   7.441 +	}
   7.442 +
   7.443 +	return true;
   7.444 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/core/LibrarySys.h	Mon Nov 24 08:39:46 2008 -0600
     8.3 @@ -0,0 +1,103 @@
     8.4 +/**
     8.5 + * vim: set ts=4 :
     8.6 + * =============================================================================
     8.7 + * SourceMod
     8.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     8.9 + * =============================================================================
    8.10 + *
    8.11 + * This program is free software; you can redistribute it and/or modify it under
    8.12 + * the terms of the GNU General Public License, version 3.0, as published by the
    8.13 + * Free Software Foundation.
    8.14 + * 
    8.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
    8.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    8.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    8.18 + * details.
    8.19 + *
    8.20 + * You should have received a copy of the GNU General Public License along with
    8.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
    8.22 + *
    8.23 + * As a special exception, AlliedModders LLC gives you permission to link the
    8.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
    8.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    8.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
    8.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
    8.28 + * this exception to all derivative works.  AlliedModders LLC defines further
    8.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    8.30 + * or <http://www.sourcemod.net/license.php>.
    8.31 + *
    8.32 + * Version: $Id$
    8.33 + */
    8.34 +
    8.35 +#ifndef _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
    8.36 +#define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
    8.37 +
    8.38 +#include <ILibrarySys.h>
    8.39 +#include "sm_platform.h"
    8.40 +
    8.41 +using namespace SourceMod;
    8.42 +
    8.43 +#if defined PLATFORM_WINDOWS
    8.44 +typedef HMODULE		LibraryHandle;
    8.45 +#elif defined PLATFORM_POSIX
    8.46 +typedef void *		LibraryHandle;
    8.47 +#endif
    8.48 +
    8.49 +class CDirectory : public IDirectory
    8.50 +{
    8.51 +public:
    8.52 +	CDirectory(const char *path);
    8.53 +	~CDirectory();
    8.54 +public:
    8.55 +	bool MoreFiles();
    8.56 +	void NextEntry();
    8.57 +	const char *GetEntryName();
    8.58 +	bool IsEntryDirectory();
    8.59 +	bool IsEntryFile();
    8.60 +	bool IsEntryValid();
    8.61 +public:
    8.62 +	bool IsValid();
    8.63 +private:
    8.64 +#if defined PLATFORM_WINDOWS
    8.65 +	HANDLE m_dir;
    8.66 +	WIN32_FIND_DATAA m_fd;
    8.67 +#elif defined PLATFORM_POSIX
    8.68 +	DIR *m_dir;
    8.69 +	struct dirent *ep;
    8.70 +	char m_origpath[PLATFORM_MAX_PATH];
    8.71 +#endif
    8.72 +};
    8.73 +
    8.74 +class CLibrary : public ILibrary
    8.75 +{
    8.76 +public:
    8.77 +	CLibrary(LibraryHandle me);
    8.78 +	~CLibrary();
    8.79 +public:
    8.80 +	void CloseLibrary();
    8.81 +	void *GetSymbolAddress(const char *symname);
    8.82 +private:
    8.83 +	LibraryHandle m_lib;
    8.84 +};
    8.85 +
    8.86 +class LibrarySystem : public ILibrarySys
    8.87 +{
    8.88 +public:
    8.89 +	ILibrary *OpenLibrary(const char *path, char *error, size_t maxlength);
    8.90 +	IDirectory *OpenDirectory(const char *path);
    8.91 +	void CloseDirectory(IDirectory *dir);
    8.92 +	bool PathExists(const char *path);
    8.93 +	bool IsPathFile(const char *path);
    8.94 +	bool IsPathDirectory(const char *path);
    8.95 +	void GetPlatformError(char *error, size_t maxlength);
    8.96 +	size_t PathFormat(char *buffer, size_t len, const char *fmt, ...);
    8.97 +	const char *GetFileExtension(const char *filename);
    8.98 +	bool CreateFolder(const char *path);
    8.99 +	size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path);
   8.100 +	bool FileTime(const char *path, FileTimeType type, time_t *pTime);
   8.101 +	void GetLoaderError(char *buffer, size_t maxlength);
   8.102 +};
   8.103 +
   8.104 +extern LibrarySystem g_LibSys;
   8.105 +
   8.106 +#endif //_INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
     9.1 --- a/core/Logger.cpp	Mon Nov 24 08:25:36 2008 -0600
     9.2 +++ b/core/Logger.cpp	Mon Nov 24 08:39:46 2008 -0600
     9.3 @@ -34,7 +34,7 @@
     9.4  #include "sourcemm_api.h"
     9.5  #include "sm_stringutil.h"
     9.6  #include "Logger.h"
     9.7 -#include "systems/LibrarySys.h"
     9.8 +#include "LibrarySys.h"
     9.9  #include "TimerSys.h"
    9.10  #include "sm_version.h"
    9.11  
    10.1 --- a/core/Makefile	Mon Nov 24 08:25:36 2008 -0600
    10.2 +++ b/core/Makefile	Mon Nov 24 08:39:46 2008 -0600
    10.3 @@ -27,9 +27,13 @@
    10.4  	smn_lang.cpp smn_player.cpp smn_string.cpp smn_sorting.cpp smn_textparse.cpp smn_timers.cpp \
    10.5  	smn_usermsgs.cpp smn_menus.cpp smn_database.cpp smn_vector.cpp smn_adt_array.cpp \
    10.6  	smn_adt_trie.cpp smn_hudtext.cpp smn_adt_stack.cpp smn_nextmap.cpp
    10.7 -OBJECTS += systems/ExtensionSys.cpp systems/ForwardSys.cpp systems/HandleSys.cpp \
    10.8 -	systems/LibrarySys.cpp systems/PluginInfoDatabase.cpp systems/PluginSys.cpp \
    10.9 -	systems/ShareSys.cpp 
   10.10 +OBJECTS += ExtensionSys.cpp 		\
   10.11 +		   ForwardSys.cpp 			\
   10.12 +		   HandleSys.cpp 			\
   10.13 +		   LibrarySys.cpp 			\
   10.14 +		   PluginInfoDatabase.cpp 	\
   10.15 +		   PluginSys.cpp 			\
   10.16 +		   ShareSys.cpp 
   10.17  OBJECTS += thread/ThreadWorker.cpp thread/BaseWorker.cpp thread/PosixThreads.cpp ThreadSupport.cpp
   10.18  
   10.19  ##############################################
    11.1 --- a/core/PlayerManager.cpp	Mon Nov 24 08:25:36 2008 -0600
    11.2 +++ b/core/PlayerManager.cpp	Mon Nov 24 08:39:46 2008 -0600
    11.3 @@ -46,7 +46,7 @@
    11.4  #include <inetchannel.h>
    11.5  #include <iclient.h>
    11.6  #include "GameConfigs.h"
    11.7 -#include "systems/ExtensionSys.h"
    11.8 +#include "ExtensionSys.h"
    11.9  
   11.10  PlayerManager g_Players;
   11.11  bool g_OnMapStarted = false;
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/core/PluginInfoDatabase.cpp	Mon Nov 24 08:39:46 2008 -0600
    12.3 @@ -0,0 +1,349 @@
    12.4 +/**
    12.5 + * vim: set ts=4 :
    12.6 + * =============================================================================
    12.7 + * SourceMod
    12.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    12.9 + * =============================================================================
   12.10 + *
   12.11 + * This program is free software; you can redistribute it and/or modify it under
   12.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   12.13 + * Free Software Foundation.
   12.14 + * 
   12.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   12.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   12.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   12.18 + * details.
   12.19 + *
   12.20 + * You should have received a copy of the GNU General Public License along with
   12.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   12.22 + *
   12.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   12.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   12.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   12.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   12.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   12.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   12.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   12.30 + * or <http://www.sourcemod.net/license.php>.
   12.31 + *
   12.32 + * Version: $Id$
   12.33 + */
   12.34 +
   12.35 +#include <stdarg.h>
   12.36 +#include <string.h>
   12.37 +#include "PluginInfoDatabase.h"
   12.38 +#include "PluginSys.h"
   12.39 +
   12.40 +void PluginSettings::Init()
   12.41 +{
   12.42 +	name = -1;
   12.43 +	pause_val = false;
   12.44 +	type_val = PluginType_MapUpdated;
   12.45 +	optarray = -1;
   12.46 +	opts_num = 0;
   12.47 +	opts_size = 0;
   12.48 +	blockload_val = false;
   12.49 +}
   12.50 +
   12.51 +/**
   12.52 + * :TODO: write the logger, make these errors log instead of being static
   12.53 + * NOTE: once we do that, we will have to change some code to ignore sections
   12.54 + */
   12.55 +
   12.56 +CPluginInfoDatabase::CPluginInfoDatabase()
   12.57 +{
   12.58 +	m_strtab = NULL;
   12.59 +	m_infodb_count = 0;
   12.60 +	m_infodb_size = 0;
   12.61 +	m_infodb = -1;
   12.62 +}
   12.63 +
   12.64 +CPluginInfoDatabase::~CPluginInfoDatabase()
   12.65 +{
   12.66 +	delete m_strtab;
   12.67 +}
   12.68 +
   12.69 +void CPluginInfoDatabase::ReadSMC_ParseStart()
   12.70 +{
   12.71 +	/* Create or reset our string table */
   12.72 +	if (m_strtab)
   12.73 +	{
   12.74 +		m_strtab->Reset();
   12.75 +	} else {
   12.76 +		m_strtab = new BaseStringTable(1024);
   12.77 +	}
   12.78 +
   12.79 +	/* Set our internal states to the beginning */
   12.80 +	in_plugins = false;
   12.81 +	cur_plugin = -1;
   12.82 +	in_options = false;
   12.83 +	m_infodb_size = 0;
   12.84 +	m_infodb_count = 0;
   12.85 +	m_infodb = -1;
   12.86 +}
   12.87 +
   12.88 +SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
   12.89 +{
   12.90 +	char buffer[512];
   12.91 +	va_list ap;
   12.92 +
   12.93 +	va_start(ap, fmt);
   12.94 +	vsnprintf(buffer, sizeof(buffer), fmt, ap);
   12.95 +	va_end(ap);
   12.96 +
   12.97 +	m_errmsg = m_strtab->AddString(buffer);
   12.98 +
   12.99 +	return SMCResult_HaltFail;
  12.100 +}
  12.101 +
  12.102 +unsigned int CPluginInfoDatabase::GetSettingsNum()
  12.103 +{
  12.104 +	return m_infodb_count;
  12.105 +}
  12.106 +
  12.107 +PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
  12.108 +{
  12.109 +	BaseMemTable *memtab = m_strtab->GetMemTable();
  12.110 +	int *table = (int *)memtab->GetAddress(m_infodb);
  12.111 +
  12.112 +	if (!table || index >= m_infodb_count)
  12.113 +	{
  12.114 +		return NULL;
  12.115 +	}
  12.116 +
  12.117 +	PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]);
  12.118 +
  12.119 +	const char *name = m_strtab->GetString(plugin->name);
  12.120 +
  12.121 +	if (!name)
  12.122 +	{
  12.123 +		return NULL;
  12.124 +	}
  12.125 +
  12.126 +	if (!g_PluginSys.TestAliasMatch(name, filename))
  12.127 +	{
  12.128 +		return NULL;
  12.129 +	}
  12.130 +
  12.131 +	return plugin;
  12.132 +}
  12.133 +
  12.134 +void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
  12.135 +{
  12.136 +	PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
  12.137 +	if (!table)
  12.138 +	{
  12.139 +		*key = NULL;
  12.140 +		*val = NULL;
  12.141 +		return;
  12.142 +	}
  12.143 +
  12.144 +	if (opt_num >= settings->opts_num)
  12.145 +	{
  12.146 +		*key = NULL;
  12.147 +		*val = NULL;
  12.148 +		return;
  12.149 +	}
  12.150 +
  12.151 +	*key = m_strtab->GetString(table[opt_num].key);
  12.152 +	*val = m_strtab->GetString(table[opt_num].val);
  12.153 +}
  12.154 +
  12.155 +SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
  12.156 +{
  12.157 +	if (cur_plugin != -1)
  12.158 +	{
  12.159 +		PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
  12.160 +		if (!in_options)
  12.161 +		{
  12.162 +			if (strcmp(key, "pause") == 0)
  12.163 +			{
  12.164 +				if (strcasecmp(value, "yes") == 0)
  12.165 +				{
  12.166 +					plugin->pause_val = true;
  12.167 +				} 
  12.168 +				else 
  12.169 +				{
  12.170 +					plugin->pause_val = false;
  12.171 +				}
  12.172 +			} 
  12.173 +			else if (strcmp(key, "lifetime") == 0) 
  12.174 +			{
  12.175 +				if (strcasecmp(value, "private") == 0)
  12.176 +				{
  12.177 +					plugin->type_val = PluginType_Private;
  12.178 +				} 
  12.179 +				else if (strcasecmp(value, "mapsync") == 0) 
  12.180 +				{
  12.181 +					plugin->type_val = PluginType_MapUpdated;
  12.182 +				}
  12.183 +				else if (strcasecmp(value, "maponly") == 0) 
  12.184 +				{
  12.185 +					plugin->type_val = PluginType_MapOnly;
  12.186 +				}
  12.187 +				else if (strcasecmp(value, "global") == 0) 
  12.188 +				{
  12.189 +					plugin->type_val = PluginType_Global;
  12.190 +				}
  12.191 +				else 
  12.192 +				{
  12.193 +					return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
  12.194 +				}
  12.195 +			}
  12.196 +			else if (strcmp(key, "blockload") == 0) 
  12.197 +			{
  12.198 +				plugin->blockload_val = true;
  12.199 +			} 
  12.200 +			else 
  12.201 +			{
  12.202 +				return MakeError("Unknown property key: \"%s\"", key);
  12.203 +			}
  12.204 +		}
  12.205 +		else 
  12.206 +		{
  12.207 +			/* Cache every option, valid or not */
  12.208 +			int keyidx = m_strtab->AddString(key);
  12.209 +			int validx = m_strtab->AddString(value);
  12.210 +			PluginOpts *table;
  12.211 +			BaseMemTable *memtab = m_strtab->GetMemTable();
  12.212 +			plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
  12.213 +			if (plugin->opts_num + 1 > plugin->opts_size)
  12.214 +			{
  12.215 +				unsigned int oldsize = plugin->opts_size;
  12.216 +				if (oldsize == 0)
  12.217 +				{
  12.218 +					//right now we don't have many
  12.219 +					plugin->opts_size = 2;
  12.220 +				} 
  12.221 +				else
  12.222 +				{
  12.223 +					plugin->opts_size *= 2;
  12.224 +				}
  12.225 +				int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
  12.226 +				/* in case it resized */
  12.227 +				plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
  12.228 +				if (plugin->optarray != -1)
  12.229 +				{
  12.230 +					void *oldtable = memtab->GetAddress(plugin->optarray);
  12.231 +					memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
  12.232 +				}
  12.233 +				plugin->optarray = newidx;
  12.234 +			}
  12.235 +			else
  12.236 +			{
  12.237 +				table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
  12.238 +			}
  12.239 +			PluginOpts *opt = &table[plugin->opts_num++];
  12.240 +			opt->key = keyidx;
  12.241 +			opt->val = validx;
  12.242 +		}
  12.243 +	}
  12.244 +	else if (in_plugins)
  12.245 +	{
  12.246 +		return MakeError("Unknown property key: \"%s\"", key);
  12.247 +	}
  12.248 +	else 
  12.249 +	{
  12.250 +		/* Ignore anything we don't know about! */
  12.251 +	}
  12.252 +
  12.253 +	return SMCResult_Continue;
  12.254 +}
  12.255 +
  12.256 +SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
  12.257 +{
  12.258 +	if (in_plugins)
  12.259 +	{
  12.260 +		if (cur_plugin != -1)
  12.261 +		{
  12.262 +			if (in_options)
  12.263 +			{
  12.264 +				in_options = false;
  12.265 +			}
  12.266 +			else 
  12.267 +			{
  12.268 +				/* If the plugin is ending, add it to the table */
  12.269 +				BaseMemTable *memtab = m_strtab->GetMemTable();
  12.270 +				int *table;
  12.271 +				if (m_infodb_count + 1 > m_infodb_size)
  12.272 +				{
  12.273 +					unsigned int oldsize = m_infodb_size;
  12.274 +					if (!m_infodb_size)
  12.275 +					{
  12.276 +						m_infodb_size = 8;
  12.277 +					}
  12.278 +					else 
  12.279 +					{
  12.280 +						m_infodb_size *= 2;
  12.281 +					}
  12.282 +					int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
  12.283 +					if (m_infodb != -1)
  12.284 +					{
  12.285 +						void *oldtable = (int *)memtab->GetAddress(m_infodb);
  12.286 +						memcpy(table, oldtable, oldsize * sizeof(int));
  12.287 +					}
  12.288 +					m_infodb = newidx;
  12.289 +				}
  12.290 +				else 
  12.291 +				{
  12.292 +					table = (int *)memtab->GetAddress(m_infodb);
  12.293 +				}
  12.294 +				/* Assign to table and scrap the current plugin */
  12.295 +				table[m_infodb_count++] = cur_plugin;
  12.296 +				cur_plugin = -1;
  12.297 +			}
  12.298 +		}
  12.299 +		else 
  12.300 +		{
  12.301 +			in_plugins = false;
  12.302 +		}
  12.303 +	}
  12.304 +
  12.305 +	return SMCResult_Continue;
  12.306 +}
  12.307 +
  12.308 +SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
  12.309 +{
  12.310 +	if (!in_plugins)
  12.311 +	{
  12.312 +		/* If we're not in the main Plugins section, and we don't get it for the name, error out */
  12.313 +		if (strcmp(name, "Plugins") != 0)
  12.314 +		{
  12.315 +			return MakeError("Unknown root section: \"%s\"", name);
  12.316 +		}
  12.317 +		else 
  12.318 +		{
  12.319 +			/* Otherwise set our states */
  12.320 +			in_plugins = true;
  12.321 +			cur_plugin = -1;
  12.322 +			in_options = false;
  12.323 +		}
  12.324 +	}
  12.325 +	else
  12.326 +	{
  12.327 +		if (cur_plugin == -1)
  12.328 +		{
  12.329 +			/* If we get a plugin node and we don't have a current plugin, create a new one */
  12.330 +			PluginSettings *plugin;
  12.331 +			int i_name = m_strtab->AddString(name);
  12.332 +			cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
  12.333 +			plugin->Init();
  12.334 +			plugin->name = i_name;
  12.335 +			in_options = false;
  12.336 +		} 
  12.337 +		else 
  12.338 +		{
  12.339 +			if (!in_options && strcmp(name, "Options") == 0)
  12.340 +			{
  12.341 +				in_options = true;
  12.342 +			}
  12.343 +			else
  12.344 +			{
  12.345 +				return MakeError("Unknown plugin sub-section: \"%s\"", name);
  12.346 +			}
  12.347 +		}
  12.348 +	}
  12.349 +
  12.350 +	return SMCResult_Continue;
  12.351 +}
  12.352 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/core/PluginInfoDatabase.h	Mon Nov 24 08:39:46 2008 -0600
    13.3 @@ -0,0 +1,106 @@
    13.4 +/**
    13.5 + * vim: set ts=4 :
    13.6 + * =============================================================================
    13.7 + * SourceMod
    13.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    13.9 + * =============================================================================
   13.10 + *
   13.11 + * This program is free software; you can redistribute it and/or modify it under
   13.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   13.13 + * Free Software Foundation.
   13.14 + * 
   13.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   13.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   13.18 + * details.
   13.19 + *
   13.20 + * You should have received a copy of the GNU General Public License along with
   13.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   13.22 + *
   13.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   13.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   13.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   13.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   13.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   13.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   13.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   13.30 + * or <http://www.sourcemod.net/license.php>.
   13.31 + *
   13.32 + * Version: $Id$
   13.33 + */
   13.34 +
   13.35 +#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
   13.36 +#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
   13.37 +
   13.38 +/**
   13.39 + * This file parses plugin_settings.cfg and stores the information in cached memory.
   13.40 + * It provides simplistic abstraction to retrieving the info.
   13.41 + * :TODO: currently untested
   13.42 + */
   13.43 +
   13.44 +#include "sm_memtable.h"
   13.45 +#include "ITextParsers.h"
   13.46 +#include "IPluginSys.h"
   13.47 +#include "sm_globals.h"
   13.48 +
   13.49 +struct PluginOpts
   13.50 +{
   13.51 +	int key;
   13.52 +	int val;
   13.53 +};
   13.54 +
   13.55 +struct PluginSettings
   13.56 +{
   13.57 +	void Init();
   13.58 +	int name;
   13.59 +	bool pause_val;
   13.60 +	PluginType type_val;
   13.61 +	int optarray;
   13.62 +	size_t opts_num;
   13.63 +	size_t opts_size;
   13.64 +	bool blockload_val;
   13.65 +};
   13.66 +
   13.67 +class CPluginInfoDatabase : public ITextListener_SMC
   13.68 +{
   13.69 +public:
   13.70 +	CPluginInfoDatabase();
   13.71 +	~CPluginInfoDatabase();
   13.72 +public: //ITextListener_SMC
   13.73 +	void ReadSMC_ParseStart();
   13.74 +	SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
   13.75 +	SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
   13.76 +	SMCResult ReadSMC_LeavingSection(const SMCStates *states);
   13.77 +public:
   13.78 +	/**
   13.79 +	 * Returns the number of plugin settings available.
   13.80 +	 */
   13.81 +	unsigned int GetSettingsNum();
   13.82 +
   13.83 +	/** 
   13.84 +	 * Given an index, returns the plugin settings block if the filename matches.
   13.85 +	 * Otherwise, returns NULL.
   13.86 +	 */
   13.87 +	PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
   13.88 +
   13.89 +	/** 
   13.90 +	 *  Given a plugin settings struct and an index,
   13.91 +	 * returns the given JIT key/value option pair at that index.
   13.92 +	 * If the input is invalid, key and val will be set to NULL.
   13.93 +	 */
   13.94 +	void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
   13.95 +private:
   13.96 +	SMCResult MakeError(const char *fmt, ...);
   13.97 +private:
   13.98 +	BaseStringTable *m_strtab;
   13.99 +	int m_errmsg;
  13.100 +	bool in_plugins;
  13.101 +	bool in_options;
  13.102 +	int m_infodb;
  13.103 +	size_t m_infodb_count;
  13.104 +	size_t m_infodb_size;
  13.105 +	int cur_plugin;
  13.106 +};
  13.107 +
  13.108 +
  13.109 +#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/core/PluginSys.cpp	Mon Nov 24 08:39:46 2008 -0600
    14.3 @@ -0,0 +1,2626 @@
    14.4 +/**
    14.5 + * vim: set ts=4 :
    14.6 + * =============================================================================
    14.7 + * SourceMod
    14.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    14.9 + * =============================================================================
   14.10 + *
   14.11 + * This program is free software; you can redistribute it and/or modify it under
   14.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   14.13 + * Free Software Foundation.
   14.14 + * 
   14.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   14.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   14.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   14.18 + * details.
   14.19 + *
   14.20 + * You should have received a copy of the GNU General Public License along with
   14.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   14.22 + *
   14.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   14.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   14.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   14.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   14.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   14.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   14.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   14.30 + * or <http://www.sourcemod.net/license.php>.
   14.31 + *
   14.32 + * Version: $Id$
   14.33 + */
   14.34 +
   14.35 +#include <stdio.h>
   14.36 +#include "PluginSys.h"
   14.37 +#include "ShareSys.h"
   14.38 +#include "LibrarySys.h"
   14.39 +#include "HandleSys.h"
   14.40 +#include "ForwardSys.h"
   14.41 +#include "sourcemm_api.h"
   14.42 +#include "sourcemod.h"
   14.43 +#include "TextParsers.h"
   14.44 +#include "Logger.h"
   14.45 +#include "ExtensionSys.h"
   14.46 +#include "sm_srvcmds.h"
   14.47 +#include "sm_stringutil.h"
   14.48 +#include "ConCmdManager.h"
   14.49 +#include "PlayerManager.h"
   14.50 +#include "CoreConfig.h"
   14.51 +#include "Translator.h"
   14.52 +
   14.53 +CPluginManager g_PluginSys;
   14.54 +HandleType_t g_PluginType = 0;
   14.55 +IdentityType_t g_PluginIdent = 0;
   14.56 +
   14.57 +CPlugin::CPlugin(const char *file)
   14.58 +{
   14.59 +	static int MySerial = 0;
   14.60 +
   14.61 +	m_type = PluginType_Private;
   14.62 +	m_status = Plugin_Uncompiled;
   14.63 +	m_serial = ++MySerial;
   14.64 +	m_pRuntime = NULL;
   14.65 +	m_errormsg[256] = '\0';
   14.66 +	snprintf(m_filename, sizeof(m_filename), "%s", file);
   14.67 +	m_handle = 0;
   14.68 +	m_ident = NULL;
   14.69 +	m_pProps = sm_trie_create();
   14.70 +	m_FakeNativesMissing = false;
   14.71 +	m_LibraryMissing = false;
   14.72 +	m_bGotAllLoaded = false;
   14.73 +	m_pPhrases = g_Translator.CreatePhraseCollection();
   14.74 +	m_MaxClientsVar = NULL;
   14.75 +}
   14.76 +
   14.77 +CPlugin::~CPlugin()
   14.78 +{
   14.79 +	if (m_handle)
   14.80 +	{
   14.81 +		HandleSecurity sec;
   14.82 +		sec.pOwner = g_PluginSys.GetIdentity();
   14.83 +		sec.pIdentity = sec.pOwner;
   14.84 +
   14.85 +		g_HandleSys.FreeHandle(m_handle, &sec);
   14.86 +		g_ShareSys.DestroyIdentity(m_ident);
   14.87 +	}
   14.88 +
   14.89 +	if (m_pRuntime != NULL)
   14.90 +	{
   14.91 +		delete m_pRuntime;
   14.92 +		m_pRuntime = NULL;
   14.93 +	}
   14.94 +
   14.95 +	if (m_pProps)
   14.96 +	{
   14.97 +		sm_trie_destroy(m_pProps);
   14.98 +	}
   14.99 +	for (size_t i=0; i<m_configs.size(); i++)
  14.100 +	{
  14.101 +		delete m_configs[i];
  14.102 +	}
  14.103 +	m_configs.clear();
  14.104 +	if (m_pPhrases != NULL)
  14.105 +	{
  14.106 +		m_pPhrases->Destroy();
  14.107 +		m_pPhrases = NULL;
  14.108 +	}
  14.109 +}
  14.110 +
  14.111 +void CPlugin::InitIdentity()
  14.112 +{
  14.113 +	if (!m_handle)
  14.114 +	{
  14.115 +		m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
  14.116 +		m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
  14.117 +		m_pRuntime->GetDefaultContext()->SetKey(1, m_ident);
  14.118 +		m_pRuntime->GetDefaultContext()->SetKey(2, (IPlugin *)this);
  14.119 +	}
  14.120 +}
  14.121 +
  14.122 +unsigned int CPlugin::CalcMemUsage()
  14.123 +{
  14.124 +	unsigned int base_size = 
  14.125 +		sizeof(CPlugin) 
  14.126 +		+ sizeof(IdentityToken_t)
  14.127 +		+ (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig)))
  14.128 +		+ sm_trie_mem_usage(m_pProps);
  14.129 +
  14.130 +	for (unsigned int i = 0; i < m_configs.size(); i++)
  14.131 +	{
  14.132 +		base_size += m_configs[i]->autocfg.size();
  14.133 +		base_size += m_configs[i]->folder.size();
  14.134 +	}
  14.135 +
  14.136 +	for (List<String>::iterator i = m_Libraries.begin();
  14.137 +		 i != m_Libraries.end();
  14.138 +		 i++)
  14.139 +	{
  14.140 +		base_size += (*i).size();
  14.141 +	}
  14.142 +
  14.143 +	for (List<String>::iterator i = m_RequiredLibs.begin();
  14.144 +		 i != m_RequiredLibs.end();
  14.145 +		 i++)
  14.146 +	{
  14.147 +		base_size += (*i).size();
  14.148 +	}
  14.149 +
  14.150 +	return base_size;
  14.151 +}
  14.152 +
  14.153 +Handle_t CPlugin::GetMyHandle()
  14.154 +{
  14.155 +	return m_handle;
  14.156 +}
  14.157 +
  14.158 +CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
  14.159 +{
  14.160 +	char fullpath[PLATFORM_MAX_PATH];
  14.161 +	g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file);
  14.162 +	FILE *fp = fopen(fullpath, "rb");
  14.163 +
  14.164 +	CPlugin *pPlugin = new CPlugin(file);
  14.165 +
  14.166 +	if (!fp)
  14.167 +	{
  14.168 +		if (error)
  14.169 +		{
  14.170 +			snprintf(error, maxlength, "Unable to open file");
  14.171 +		}
  14.172 +		pPlugin->m_status = Plugin_BadLoad;
  14.173 +		return pPlugin;
  14.174 +	}
  14.175 +
  14.176 +	fclose(fp);
  14.177 +
  14.178 +	return pPlugin;
  14.179 +}
  14.180 +
  14.181 +bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */)
  14.182 +{
  14.183 +	bool exists = sm_trie_retrieve(m_pProps, prop, ptr);
  14.184 +
  14.185 +	if (exists && remove)
  14.186 +	{
  14.187 +		sm_trie_delete(m_pProps, prop);
  14.188 +	}
  14.189 +
  14.190 +	return exists;
  14.191 +}
  14.192 +
  14.193 +bool CPlugin::SetProperty(const char *prop, void *ptr)
  14.194 +{
  14.195 +	return sm_trie_insert(m_pProps, prop, ptr);
  14.196 +}
  14.197 +
  14.198 +IPluginRuntime *CPlugin::GetRuntime()
  14.199 +{
  14.200 +	return m_pRuntime;
  14.201 +}
  14.202 +
  14.203 +void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
  14.204 +{
  14.205 +	PluginStatus old_status = m_status;
  14.206 +	m_status = status;
  14.207 +
  14.208 +	if (old_status == Plugin_Running)
  14.209 +	{
  14.210 +		/* Tell everyone we're now paused */
  14.211 +		g_PluginSys._SetPauseState(this, true);
  14.212 +	}
  14.213 +
  14.214 +	va_list ap;
  14.215 +	va_start(ap, error_fmt);
  14.216 +	vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
  14.217 +	va_end(ap);
  14.218 +
  14.219 +	if (m_pRuntime != NULL)
  14.220 +	{
  14.221 +		m_pRuntime->SetPauseState(true);
  14.222 +	}
  14.223 +}
  14.224 +
  14.225 +bool CPlugin::UpdateInfo()
  14.226 +{
  14.227 +	/* Now grab the info */
  14.228 +	uint32_t idx;
  14.229 +	IPluginContext *base = GetBaseContext();
  14.230 +	int err = base->FindPubvarByName("myinfo", &idx);
  14.231 +
  14.232 +	memset(&m_info, 0, sizeof(m_info));
  14.233 +
  14.234 +	if (err == SP_ERROR_NONE)
  14.235 +	{
  14.236 +		struct sm_plugininfo_c_t
  14.237 +		{
  14.238 +			cell_t name;
  14.239 +			cell_t description;
  14.240 +			cell_t author;
  14.241 +			cell_t version;
  14.242 +			cell_t url;
  14.243 +		};
  14.244 +		sm_plugininfo_c_t *cinfo;
  14.245 +		cell_t local_addr;
  14.246 +
  14.247 +		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
  14.248 +		base->LocalToString(cinfo->name, (char **)&m_info.name);
  14.249 +		base->LocalToString(cinfo->description, (char **)&m_info.description);
  14.250 +		base->LocalToString(cinfo->author, (char **)&m_info.author);
  14.251 +		base->LocalToString(cinfo->url, (char **)&m_info.url);
  14.252 +		base->LocalToString(cinfo->version, (char **)&m_info.version);
  14.253 +	}
  14.254 +
  14.255 +	m_info.author = m_info.author ? m_info.author : "";
  14.256 +	m_info.description = m_info.description ? m_info.description : "";
  14.257 +	m_info.name = m_info.name ? m_info.name : "";
  14.258 +	m_info.url = m_info.url ? m_info.url : "";
  14.259 +	m_info.version = m_info.version ? m_info.version : "";
  14.260 +
  14.261 +	if ((err = base->FindPubvarByName("__version", &idx)) == SP_ERROR_NONE)
  14.262 +	{
  14.263 +		struct __version_info
  14.264 +		{
  14.265 +			cell_t version;
  14.266 +			cell_t filevers;
  14.267 +			cell_t date;
  14.268 +			cell_t time;
  14.269 +		};
  14.270 +		__version_info *info;
  14.271 +		cell_t local_addr;
  14.272 +		const char *pDate, *pTime, *pFileVers;
  14.273 +
  14.274 +		pDate = "";
  14.275 +		pTime = "";
  14.276 +
  14.277 +		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
  14.278 +		m_FileVersion = info->version;
  14.279 +		if (m_FileVersion >= 3)
  14.280 +		{
  14.281 +			base->LocalToString(info->date, (char **)&pDate);
  14.282 +			base->LocalToString(info->time, (char **)&pTime);
  14.283 +			UTIL_Format(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
  14.284 +		}
  14.285 +		if (m_FileVersion > 4)
  14.286 +		{
  14.287 +			base->LocalToString(info->filevers, (char **)&pFileVers);
  14.288 +			SetErrorState(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
  14.289 +			return false;
  14.290 +		}
  14.291 +	}
  14.292 +	else
  14.293 +	{
  14.294 +		m_FileVersion = 0;
  14.295 +	}
  14.296 +
  14.297 +	if ((err = base->FindPubvarByName("MaxClients", &idx)) == SP_ERROR_NONE)
  14.298 +	{
  14.299 +		base->GetPubvarByIndex(idx, &m_MaxClientsVar);
  14.300 +	}
  14.301 +
  14.302 +	return true;
  14.303 +}
  14.304 +
  14.305 +void CPlugin::SyncMaxClients(int max_clients)
  14.306 +{
  14.307 +	if (m_MaxClientsVar == NULL)
  14.308 +	{
  14.309 +		return;
  14.310 +	}
  14.311 +
  14.312 +	*m_MaxClientsVar->offs = max_clients;
  14.313 +}
  14.314 +
  14.315 +void CPlugin::Call_OnPluginStart()
  14.316 +{
  14.317 +	if (m_status != Plugin_Loaded)
  14.318 +	{
  14.319 +		return;
  14.320 +	}
  14.321 +
  14.322 +	m_status = Plugin_Running;
  14.323 +
  14.324 +	SyncMaxClients(g_Players.MaxClients());
  14.325 +
  14.326 +	cell_t result;
  14.327 +	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginStart");
  14.328 +	if (!pFunction)
  14.329 +	{
  14.330 +		return;
  14.331 +	}
  14.332 +
  14.333 +	int err;
  14.334 +	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
  14.335 +	{
  14.336 +		SetErrorState(Plugin_Error, "Error detected in plugin startup (see error logs)");
  14.337 +	}
  14.338 +}
  14.339 +
  14.340 +void CPlugin::Call_OnPluginEnd()
  14.341 +{
  14.342 +	if (m_status > Plugin_Paused)
  14.343 +	{
  14.344 +		return;
  14.345 +	}
  14.346 +
  14.347 +	cell_t result;
  14.348 +	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginEnd");
  14.349 +	if (!pFunction)
  14.350 +	{
  14.351 +		return;
  14.352 +	}
  14.353 +
  14.354 +	pFunction->Execute(&result);
  14.355 +}
  14.356 +
  14.357 +void CPlugin::Call_OnAllPluginsLoaded()
  14.358 +{
  14.359 +	if (m_status > Plugin_Paused)
  14.360 +	{
  14.361 +		return;
  14.362 +	}
  14.363 +
  14.364 +	if (m_bGotAllLoaded)
  14.365 +	{
  14.366 +		return;
  14.367 +	}
  14.368 +
  14.369 +	m_bGotAllLoaded = true;
  14.370 +
  14.371 +	cell_t result;
  14.372 +	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnAllPluginsLoaded");
  14.373 +	if (pFunction != NULL)
  14.374 +	{
  14.375 +		pFunction->Execute(&result);
  14.376 +	}
  14.377 +
  14.378 +	if (g_OnMapStarted)
  14.379 +	{
  14.380 +		if ((pFunction = m_pRuntime->GetFunctionByName("OnMapStart")) != NULL)
  14.381 +		{
  14.382 +			pFunction->Execute(NULL);
  14.383 +		}
  14.384 +	}
  14.385 +
  14.386 +	if (SM_AreConfigsExecuted())
  14.387 +	{
  14.388 +		SM_ExecuteForPlugin(GetBaseContext());
  14.389 +	}
  14.390 +}
  14.391 +
  14.392 +bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
  14.393 +{
  14.394 +	if (m_status != Plugin_Created)
  14.395 +	{
  14.396 +		return false;
  14.397 +	}
  14.398 +
  14.399 +	m_status = Plugin_Loaded;
  14.400 +
  14.401 +	int err;
  14.402 +	cell_t result;
  14.403 +	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("AskPluginLoad");
  14.404 +
  14.405 +	if (!pFunction)
  14.406 +	{
  14.407 +		return true;
  14.408 +	}
  14.409 +
  14.410 +	pFunction->PushCell(m_handle);
  14.411 +	pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
  14.412 +	pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
  14.413 +	pFunction->PushCell(maxlength);
  14.414 +	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
  14.415 +	{
  14.416 +		return false;
  14.417 +	}
  14.418 +
  14.419 +	if (!result || m_status != Plugin_Loaded)
  14.420 +	{
  14.421 +		return false;
  14.422 +	}
  14.423 +
  14.424 +	return true;
  14.425 +}
  14.426 +
  14.427 +void *CPlugin::GetPluginStructure()
  14.428 +{
  14.429 +	return NULL;
  14.430 +}
  14.431 +
  14.432 +IPluginContext *CPlugin::GetBaseContext()
  14.433 +{
  14.434 +	if (m_pRuntime == NULL)
  14.435 +	{
  14.436 +		return NULL;
  14.437 +	}
  14.438 +
  14.439 +	return m_pRuntime->GetDefaultContext();
  14.440 +}
  14.441 +
  14.442 +sp_context_t *CPlugin::GetContext()
  14.443 +{
  14.444 +	return NULL;
  14.445 +}
  14.446 +
  14.447 +const char *CPlugin::GetFilename()
  14.448 +{
  14.449 +	return m_filename;
  14.450 +}
  14.451 +
  14.452 +PluginType CPlugin::GetType()
  14.453 +{
  14.454 +	return m_type;
  14.455 +}
  14.456 +
  14.457 +const sm_plugininfo_t *CPlugin::GetPublicInfo()
  14.458 +{
  14.459 +	if (GetStatus() >= Plugin_Created)
  14.460 +	{
  14.461 +		return NULL;
  14.462 +	}
  14.463 +	return &m_info;
  14.464 +}
  14.465 +
  14.466 +unsigned int CPlugin::GetSerial()
  14.467 +{
  14.468 +	return m_serial;
  14.469 +}
  14.470 +
  14.471 +PluginStatus CPlugin::GetStatus()
  14.472 +{
  14.473 +	return m_status;
  14.474 +}
  14.475 +
  14.476 +bool CPlugin::IsDebugging()
  14.477 +{
  14.478 +	if (m_pRuntime == NULL)
  14.479 +	{
  14.480 +		return false;
  14.481 +	}
  14.482 +
  14.483 +	return true;
  14.484 +}
  14.485 +
  14.486 +void CPlugin::LibraryActions(bool dropping)
  14.487 +{
  14.488 +	List<String>::iterator iter;
  14.489 +	for (iter = m_Libraries.begin();
  14.490 +		iter != m_Libraries.end();
  14.491 +		iter++)
  14.492 +	{
  14.493 +		g_PluginSys.OnLibraryAction((*iter).c_str(), true, dropping);
  14.494 +	}
  14.495 +}
  14.496 +
  14.497 +bool CPlugin::SetPauseState(bool paused)
  14.498 +{
  14.499 +	if (paused && GetStatus() != Plugin_Running)
  14.500 +	{
  14.501 +		return false;
  14.502 +	} else if (!paused && GetStatus() != Plugin_Paused) {
  14.503 +		return false;
  14.504 +	}
  14.505 +
  14.506 +	if (paused)
  14.507 +	{
  14.508 +		LibraryActions(true);
  14.509 +	}
  14.510 +
  14.511 +	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginPauseChange");
  14.512 +	if (pFunction)
  14.513 +	{
  14.514 +		cell_t result;
  14.515 +		pFunction->PushCell(paused ? 1 : 0);
  14.516 +		pFunction->Execute(&result);
  14.517 +	}
  14.518 +
  14.519 +	if (paused)
  14.520 +	{
  14.521 +		m_status = Plugin_Paused;
  14.522 +		m_pRuntime->SetPauseState(true);
  14.523 +	} else {
  14.524 +		m_status = Plugin_Running;
  14.525 +		m_pRuntime->SetPauseState(false);
  14.526 +	}
  14.527 +
  14.528 +	g_PluginSys._SetPauseState(this, paused);
  14.529 +
  14.530 +	if (!paused)
  14.531 +	{
  14.532 +		LibraryActions(false);
  14.533 +	}
  14.534 +
  14.535 +	return true;
  14.536 +}
  14.537 +
  14.538 +IdentityToken_t *CPlugin::GetIdentity()
  14.539 +{
  14.540 +	return m_ident;
  14.541 +}
  14.542 +
  14.543 +bool CPlugin::IsRunnable()
  14.544 +{
  14.545 +	return (m_status <= Plugin_Paused) ? true : false;
  14.546 +}
  14.547 +
  14.548 +time_t CPlugin::GetFileTimeStamp()
  14.549 +{
  14.550 +	char path[PLATFORM_MAX_PATH];
  14.551 +	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename);
  14.552 +#ifdef PLATFORM_WINDOWS
  14.553 +	struct _stat s;
  14.554 +	if (_stat(path, &s) != 0)
  14.555 +#elif defined PLATFORM_POSIX
  14.556 +	struct stat s;
  14.557 +	if (stat(path, &s) != 0)
  14.558 +#endif
  14.559 +	{
  14.560 +		return 0;
  14.561 +	}
  14.562 +	else
  14.563 +	{
  14.564 +		return s.st_mtime;
  14.565 +	}
  14.566 +}
  14.567 +
  14.568 +time_t CPlugin::GetTimeStamp()
  14.569 +{
  14.570 +	return m_LastAccess;
  14.571 +}
  14.572 +
  14.573 +void CPlugin::SetTimeStamp(time_t t)
  14.574 +{
  14.575 +	m_LastAccess = t;
  14.576 +}
  14.577 +
  14.578 +IPhraseCollection *CPlugin::GetPhrases()
  14.579 +{
  14.580 +	return m_pPhrases;
  14.581 +}
  14.582 +
  14.583 +void CPlugin::DependencyDropped(CPlugin *pOwner)
  14.584 +{
  14.585 +	if (!m_pRuntime)
  14.586 +	{
  14.587 +		return;
  14.588 +	}
  14.589 +
  14.590 +	List<String>::iterator reqlib_iter;
  14.591 +	List<String>::iterator lib_iter;
  14.592 +	for (lib_iter=pOwner->m_Libraries.begin(); lib_iter!=pOwner->m_Libraries.end(); lib_iter++)
  14.593 +	{
  14.594 +		for (reqlib_iter=m_RequiredLibs.begin(); reqlib_iter!=m_RequiredLibs.end(); reqlib_iter++)
  14.595 +		{
  14.596 +			if ((*reqlib_iter) == (*lib_iter))
  14.597 +			{
  14.598 +				m_LibraryMissing = true;
  14.599 +			}
  14.600 +		}	
  14.601 +	}
  14.602 +
  14.603 +	List<NativeEntry *>::iterator iter;
  14.604 +	NativeEntry *pNative;
  14.605 +	sp_native_t *native;
  14.606 +	uint32_t idx;
  14.607 +	unsigned int unbound = 0;
  14.608 +
  14.609 +	for (iter = pOwner->m_Natives.begin();
  14.610 +		 iter != pOwner->m_Natives.end();
  14.611 +		 iter++)
  14.612 +	{
  14.613 +		pNative = (*iter);
  14.614 +		/* Find this native! */
  14.615 +		if (m_pRuntime->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE)
  14.616 +		{
  14.617 +			continue;
  14.618 +		}
  14.619 +		/* Unbind it */
  14.620 +		m_pRuntime->GetNativeByIndex(idx, &native);
  14.621 +		native->pfn = NULL;
  14.622 +		native->status = SP_NATIVE_UNBOUND;
  14.623 +		unbound++;
  14.624 +	}
  14.625 +
  14.626 +	if (unbound)
  14.627 +	{
  14.628 +		m_FakeNativesMissing = true;
  14.629 +	}
  14.630 +
  14.631 +	/* :IDEA: in the future, add native trapping? */
  14.632 +	if (m_FakeNativesMissing || m_LibraryMissing)
  14.633 +	{
  14.634 +		SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
  14.635 +	}
  14.636 +}
  14.637 +
  14.638 +unsigned int CPlugin::GetConfigCount()
  14.639 +{
  14.640 +	return (unsigned int)m_configs.size();
  14.641 +}
  14.642 +
  14.643 +AutoConfig *CPlugin::GetConfig(unsigned int i)
  14.644 +{
  14.645 +	if (i >= GetConfigCount())
  14.646 +	{
  14.647 +		return NULL;
  14.648 +	}
  14.649 +
  14.650 +	return m_configs[i];
  14.651 +}
  14.652 +
  14.653 +void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder)
  14.654 +{
  14.655 +	/* Do a check for duplicates to prevent double-execution */
  14.656 +	for (size_t i = 0; i < m_configs.size(); i++)
  14.657 +	{
  14.658 +		if (m_configs[i]->autocfg.compare(cfg) == 0
  14.659 +			&& m_configs[i]->folder.compare(folder) == 0
  14.660 +			&& m_configs[i]->create == autoCreate)
  14.661 +		{
  14.662 +			return;
  14.663 +		}
  14.664 +	}
  14.665 +
  14.666 +	AutoConfig *c = new AutoConfig;
  14.667 +
  14.668 +	c->autocfg = cfg;
  14.669 +	c->folder = folder;
  14.670 +	c->create = autoCreate;
  14.671 +
  14.672 +	m_configs.push_back(c);
  14.673 +}
  14.674 +
  14.675 +void CPlugin::DropEverything()
  14.676 +{
  14.677 +	CPlugin *pOther;
  14.678 +	List<CPlugin *>::iterator iter;
  14.679 +	List<WeakNative>::iterator wk_iter;
  14.680 +
  14.681 +	/* Tell everyone that depends on us that we're about to drop */
  14.682 +	for (iter = m_Dependents.begin();
  14.683 +		 iter != m_Dependents.end(); 
  14.684 +		 iter++)
  14.685 +	{
  14.686 +		pOther = (*iter);
  14.687 +		pOther->DependencyDropped(this);
  14.688 +	}
  14.689 +
  14.690 +	/* Note: we don't care about things we depend on. 
  14.691 +	 * The reason is that extensions have their own cleanup 
  14.692 +	 * code for plugins.  Although the "right" design would be 
  14.693 +	 * to centralize that here, i'm omitting it for now.  Thus, 
  14.694 +	 * the code below to walk the plugins list will suffice.
  14.695 +	 */
  14.696 +	
  14.697 +	/* Other plugins could be holding weak references that were 
  14.698 +	 * added by us.  We need to clean all of those up now.
  14.699 +	 */
  14.700 +	for (iter = g_PluginSys.m_plugins.begin();
  14.701 +		 iter != g_PluginSys.m_plugins.end();
  14.702 +		 iter++)
  14.703 +	{
  14.704 +		(*iter)->DropRefsTo(this);
  14.705 +	}
  14.706 +
  14.707 +	/* Proceed with the rest of the necessities. */
  14.708 +	CNativeOwner::DropEverything();
  14.709 +}
  14.710 +
  14.711 +bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
  14.712 +{
  14.713 +	NativeEntry *pEntry;
  14.714 +
  14.715 +	if ((pEntry = g_ShareSys.AddFakeNative(pFunc, name, func)) == NULL)
  14.716 +	{
  14.717 +		return false;
  14.718 +	}
  14.719 +
  14.720 +	m_Natives.push_back(pEntry);
  14.721 +
  14.722 +	return true;
  14.723 +}
  14.724 +
  14.725 +/*******************
  14.726 + * PLUGIN ITERATOR *
  14.727 + *******************/
  14.728 +
  14.729 +CPluginManager::CPluginIterator::CPluginIterator(List<CPlugin *> *_mylist)
  14.730 +{
  14.731 +	mylist = _mylist;
  14.732 +	Reset();
  14.733 +}
  14.734 +
  14.735 +IPlugin *CPluginManager::CPluginIterator::GetPlugin()
  14.736 +{
  14.737 +	return (*current);
  14.738 +}
  14.739 +
  14.740 +bool CPluginManager::CPluginIterator::MorePlugins()
  14.741 +{
  14.742 +	return (current != mylist->end());
  14.743 +}
  14.744 +
  14.745 +void CPluginManager::CPluginIterator::NextPlugin()
  14.746 +{
  14.747 +	current++;
  14.748 +}
  14.749 +
  14.750 +void CPluginManager::CPluginIterator::Release()
  14.751 +{
  14.752 +	g_PluginSys.ReleaseIterator(this);
  14.753 +}
  14.754 +
  14.755 +CPluginManager::CPluginIterator::~CPluginIterator()
  14.756 +{
  14.757 +}
  14.758 +
  14.759 +void CPluginManager::CPluginIterator::Reset()
  14.760 +{
  14.761 +	current = mylist->begin();
  14.762 +}
  14.763 +
  14.764 +/******************
  14.765 + * PLUGIN MANAGER *
  14.766 + ******************/
  14.767 +
  14.768 +CPluginManager::CPluginManager()
  14.769 +{
  14.770 +	m_LoadLookup = sm_trie_create();
  14.771 +	m_AllPluginsLoaded = false;
  14.772 +	m_MyIdent = NULL;
  14.773 +	m_LoadingLocked = false;
  14.774 +}
  14.775 +
  14.776 +CPluginManager::~CPluginManager()
  14.777 +{
  14.778 +	/* :NOTICE: 
  14.779 +	 * Ignore the fact that there might be plugins in the cache.
  14.780 +	 * This usually means that Core is not being unloaded properly, and everything
  14.781 +	 * will crash anyway.  YAY
  14.782 +	 */
  14.783 +	sm_trie_destroy(m_LoadLookup);
  14.784 +
  14.785 +	CStack<CPluginManager::CPluginIterator *>::iterator iter;
  14.786 +	for (iter=m_iters.begin(); iter!=m_iters.end(); iter++)
  14.787 +	{
  14.788 +		delete (*iter);
  14.789 +	}
  14.790 +	m_iters.popall();
  14.791 +}
  14.792 +
  14.793 +void CPluginManager::Shutdown()
  14.794 +{
  14.795 +	List<CPlugin *>::iterator iter;
  14.796 +
  14.797 +	while ((iter = m_plugins.begin()) != m_plugins.end())
  14.798 +	{
  14.799 +		UnloadPlugin(*iter);
  14.800 +	}
  14.801 +}
  14.802 +
  14.803 +void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
  14.804 +{
  14.805 +	/* First read in the database of plugin settings */
  14.806 +	SMCError err;
  14.807 +	SMCStates states;
  14.808 +	m_AllPluginsLoaded = false;
  14.809 +	if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &states)) != SMCError_Okay)
  14.810 +	{
  14.811 +		g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
  14.812 +		const char *err_msg = textparsers->GetSMCErrorString(err);
  14.813 +		if (err_msg)
  14.814 +		{
  14.815 +			g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
  14.816 +		}
  14.817 +	}
  14.818 +
  14.819 +	LoadPluginsFromDir(basedir, NULL);
  14.820 +}
  14.821 +
  14.822 +void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
  14.823 +{
  14.824 +	char base_path[PLATFORM_MAX_PATH];
  14.825 +
  14.826 +	/* Form the current path to start reading from */
  14.827 +	if (localpath == NULL)
  14.828 +	{
  14.829 +		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
  14.830 +	} else {
  14.831 +		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
  14.832 +	}
  14.833 +
  14.834 +	IDirectory *dir = g_LibSys.OpenDirectory(base_path);
  14.835 +
  14.836 +	if (!dir)
  14.837 +	{
  14.838 +		char error[256];
  14.839 +		g_LibSys.GetPlatformError(error, sizeof(error));
  14.840 +		g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
  14.841 +		g_Logger.LogError("[SM] Platform returned error: %s", error);
  14.842 +		return;
  14.843 +	}
  14.844 +
  14.845 +	while (dir->MoreFiles())
  14.846 +	{
  14.847 +		if (dir->IsEntryDirectory() 
  14.848 +			&& (strcmp(dir->GetEntryName(), ".") != 0)
  14.849 +			&& (strcmp(dir->GetEntryName(), "..") != 0)
  14.850 +			&& (strcmp(dir->GetEntryName(), "disabled") != 0)
  14.851 +			&& (strcmp(dir->GetEntryName(), "optional") != 0))
  14.852 +		{
  14.853 +			char new_local[PLATFORM_MAX_PATH];
  14.854 +			if (localpath == NULL)
  14.855 +			{
  14.856 +				/* If no path yet, don't add a former slash */
  14.857 +				snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
  14.858 +			} else {
  14.859 +				g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
  14.860 +			}
  14.861 +			LoadPluginsFromDir(basedir, new_local);
  14.862 +		} else if (dir->IsEntryFile()) {
  14.863 +			const char *name = dir->GetEntryName();
  14.864 +			size_t len = strlen(name);
  14.865 +			if (len >= 4
  14.866 +				&& strcmp(&name[len-4], ".smx") == 0)
  14.867 +			{
  14.868 +				/* If the filename matches, load the plugin */
  14.869 +				char plugin[PLATFORM_MAX_PATH];
  14.870 +				if (localpath == NULL)
  14.871 +				{
  14.872 +					snprintf(plugin, sizeof(plugin), "%s", name);
  14.873 +				} else {
  14.874 +					g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
  14.875 +				}
  14.876 +				LoadAutoPlugin(plugin);
  14.877 +			}
  14.878 +		}
  14.879 +		dir->NextEntry();
  14.880 +	}
  14.881 +	g_LibSys.CloseDirectory(dir);
  14.882 +}
  14.883 +
  14.884 +LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
  14.885 +{
  14.886 +	if (m_LoadingLocked)
  14.887 +	{
  14.888 +		return LoadRes_NeverLoad;
  14.889 +	}
  14.890 +
  14.891 +	int err;
  14.892 +	bool no_load = false;
  14.893 +	PluginSettings *pset;
  14.894 +	unsigned int setcount = m_PluginInfo.GetSettingsNum();
  14.895 +	for (unsigned int i=0; i<setcount; i++)
  14.896 +	{
  14.897 +		if ((pset = m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
  14.898 +		{
  14.899 +			continue;
  14.900 +		}
  14.901 +		if (pset->blockload_val)
  14.902 +		{
  14.903 +			no_load = true;
  14.904 +			break;
  14.905 +		}
  14.906 +	}
  14.907 +
  14.908 +	/**
  14.909 +	 * Does this plugin already exist?
  14.910 +	 */
  14.911 +	CPlugin *pPlugin;
  14.912 +	if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
  14.913 +	{
  14.914 +		/* Check to see if we should try reloading it */
  14.915 +		if (pPlugin->GetStatus() == Plugin_BadLoad
  14.916 +			|| pPlugin->GetStatus() == Plugin_Error
  14.917 +			|| pPlugin->GetStatus() == Plugin_Failed
  14.918 +			|| no_load)
  14.919 +		{
  14.920 +			UnloadPlugin(pPlugin);
  14.921 +		}
  14.922 +		else
  14.923 +		{
  14.924 +			if (_plugin)
  14.925 +			{
  14.926 +				*_plugin = pPlugin;
  14.927 +			}
  14.928 +			return LoadRes_AlreadyLoaded;
  14.929 +		}
  14.930 +	}
  14.931 +
  14.932 +	if (no_load)
  14.933 +	{
  14.934 +		return LoadRes_NeverLoad;
  14.935 +	}
  14.936 +
  14.937 +	pPlugin = CPlugin::CreatePlugin(path, error, maxlength);
  14.938 +
  14.939 +	assert(pPlugin != NULL);
  14.940 +
  14.941 +	pPlugin->m_type = PluginType_MapUpdated;
  14.942 +
  14.943 +	ICompilation *co = NULL;
  14.944 +
  14.945 +	if (pPlugin->m_status == Plugin_Uncompiled)
  14.946 +	{
  14.947 +		co = g_pSourcePawn2->StartCompilation();
  14.948 +	}
  14.949 +
  14.950 +	for (unsigned int i=0; i<setcount; i++)
  14.951 +	{
  14.952 +		if ((pset=m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
  14.953 +		{
  14.954 +			continue;
  14.955 +		}
  14.956 +		pPlugin->m_type = pset->type_val;
  14.957 +		if (co)
  14.958 +		{
  14.959 +			for (unsigned int j=0; j<pset->opts_num; j++)
  14.960 +			{
  14.961 +				const char *key, *val;
  14.962 +				m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
  14.963 +				if (!key || !val)
  14.964 +				{
  14.965 +					continue;
  14.966 +				}
  14.967 +				if ((err = co->SetOption(key, val)) == SP_ERROR_NONE)
  14.968 +				{
  14.969 +					if (error)
  14.970 +					{
  14.971 +						snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
  14.972 +					}
  14.973 +					co->Abort();
  14.974 +					co = NULL;
  14.975 +					break;
  14.976 +				}
  14.977 +			}
  14.978 +		}
  14.979 +	}
  14.980 +
  14.981 +	/* Do the actual compiling */
  14.982 +	if (co != NULL)
  14.983 +	{
  14.984 +		char fullpath[PLATFORM_MAX_PATH];
  14.985 +		g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", pPlugin->m_filename);
  14.986 +
  14.987 +		pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(co, fullpath, &err);
  14.988 +		if (pPlugin->m_pRuntime == NULL)
  14.989 +		{
  14.990 +			snprintf(error, 
  14.991 +				maxlength, 
  14.992 +				"Unable to load plugin (error %d: %s)", 
  14.993 +				err, 
  14.994 +				g_pSourcePawn2->GetErrorString(err));
  14.995 +			pPlugin->m_status = Plugin_BadLoad;
  14.996 +		}
  14.997 +		else
  14.998 +		{
  14.999 +			if (pPlugin->UpdateInfo())
 14.1000 +			{
 14.1001 +				pPlugin->m_status = Plugin_Created;
 14.1002 +			}
 14.1003 +			else
 14.1004 +			{
 14.1005 +				UTIL_Format(error, maxlength, "%s", pPlugin->m_errormsg);
 14.1006 +			}
 14.1007 +		}
 14.1008 +	}
 14.1009 +
 14.1010 +	/* Get the status */
 14.1011 +	if (pPlugin->GetStatus() == Plugin_Created)
 14.1012 +	{
 14.1013 +		/* First native pass - add anything from Core */
 14.1014 +		g_ShareSys.BindNativesToPlugin(pPlugin, true);
 14.1015 +		pPlugin->InitIdentity();
 14.1016 +		if (pPlugin->Call_AskPluginLoad(error, maxlength))
 14.1017 +		{
 14.1018 +			/* Autoload any modules */
 14.1019 +			LoadOrRequireExtensions(pPlugin, 1, error, maxlength);
 14.1020 +		}
 14.1021 +		else
 14.1022 +		{
 14.1023 +			pPlugin->SetErrorState(Plugin_Failed, "%s", error);
 14.1024 +		}
 14.1025 +	}
 14.1026 +
 14.1027 +	/* Save the time stamp */
 14.1028 +	time_t t = pPlugin->GetFileTimeStamp();
 14.1029 +	pPlugin->SetTimeStamp(t);
 14.1030 +
 14.1031 +	if (_plugin)
 14.1032 +	{
 14.1033 +		*_plugin = pPlugin;
 14.1034 +	}
 14.1035 +
 14.1036 +	return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure;
 14.1037 +}
 14.1038 +
 14.1039 +IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded)
 14.1040 +{
 14.1041 +	CPlugin *pl;
 14.1042 +	LoadRes res;
 14.1043 +
 14.1044 +	*wasloaded = false;
 14.1045 +	if ((res=_LoadPlugin(&pl, path, true, type, error, maxlength)) == LoadRes_Failure)
 14.1046 +	{
 14.1047 +		delete pl;
 14.1048 +		return NULL;
 14.1049 +	}
 14.1050 +
 14.1051 +	if (res == LoadRes_AlreadyLoaded)
 14.1052 +	{
 14.1053 +		*wasloaded = true;
 14.1054 +		return pl;
 14.1055 +	}
 14.1056 +
 14.1057 +	if (res == LoadRes_NeverLoad)
 14.1058 +	{
 14.1059 +		if (m_LoadingLocked)
 14.1060 +		{
 14.1061 +			UTIL_Format(error, maxlength, "There is a global plugin loading lock in effect");
 14.1062 +		}
 14.1063 +		else
 14.1064 +		{
 14.1065 +			UTIL_Format(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
 14.1066 +		}
 14.1067 +		return NULL;
 14.1068 +	}
 14.1069 +
 14.1070 +	AddPlugin(pl);
 14.1071 +
 14.1072 +	/* Run second pass if we need to */
 14.1073 +	if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
 14.1074 +	{
 14.1075 +		if (!RunSecondPass(pl, error, maxlength))
 14.1076 +		{
 14.1077 +			UnloadPlugin(pl);
 14.1078 +			return NULL;
 14.1079 +		}
 14.1080 +		pl->Call_OnAllPluginsLoaded();
 14.1081 +	}
 14.1082 +
 14.1083 +	return pl;
 14.1084 +}
 14.1085 +
 14.1086 +void CPluginManager::LoadAutoPlugin(const char *plugin)
 14.1087 +{
 14.1088 +	CPlugin *pl = NULL;
 14.1089 +	LoadRes res;
 14.1090 +	char error[255] = "Unknown error";
 14.1091 +
 14.1092 +	if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
 14.1093 +	{
 14.1094 +		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
 14.1095 +		pl->SetErrorState(
 14.1096 +			pl->GetStatus() == Plugin_BadLoad ? Plugin_BadLoad : Plugin_Failed, 
 14.1097 +			"%s",
 14.1098 +			error);
 14.1099 +	}
 14.1100 +
 14.1101 +	if (res == LoadRes_Successful || res == LoadRes_Failure)
 14.1102 +	{
 14.1103 +		AddPlugin(pl);
 14.1104 +	}
 14.1105 +}
 14.1106 +
 14.1107 +void CPluginManager::AddPlugin(CPlugin *pPlugin)
 14.1108 +{
 14.1109 +	List<IPluginsListener *>::iterator iter;
 14.1110 +	IPluginsListener *pListener;
 14.1111 +
 14.1112 +	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 14.1113 +	{
 14.1114 +		pListener = (*iter);
 14.1115 +		pListener->OnPluginCreated(pPlugin);
 14.1116 +	}
 14.1117 +
 14.1118 +	m_plugins.push_back(pPlugin);
 14.1119 +	sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
 14.1120 +}
 14.1121 +
 14.1122 +void CPluginManager::LoadAll_SecondPass()
 14.1123 +{
 14.1124 +	List<CPlugin *>::iterator iter;
 14.1125 +	CPlugin *pPlugin;
 14.1126 +
 14.1127 +	char error[256];
 14.1128 +	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 14.1129 +	{
 14.1130 +		pPlugin = (*iter);
 14.1131 +		if (pPlugin->GetStatus() == Plugin_Loaded)
 14.1132 +		{
 14.1133 +			error[0] = '\0';
 14.1134 +			if (!RunSecondPass(pPlugin, error, sizeof(error)))
 14.1135 +			{
 14.1136 +				g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
 14.1137 +				pPlugin->SetErrorState(Plugin_Failed, "%s", error);
 14.1138 +			}
 14.1139 +		}
 14.1140 +	}
 14.1141 +
 14.1142 +	m_AllPluginsLoaded = true;
 14.1143 +}
 14.1144 +
 14.1145 +bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength)
 14.1146 +{
 14.1147 +	struct _pl
 14.1148 +	{
 14.1149 +		cell_t name;
 14.1150 +		cell_t file;
 14.1151 +		cell_t required;
 14.1152 +	} *pl;
 14.1153 +
 14.1154 +	IPluginContext *pBase = pPlugin->GetBaseContext();
 14.1155 +	uint32_t num = pBase->GetPubVarsNum();
 14.1156 +	sp_pubvar_t *pubvar;
 14.1157 +	char *name, *file;
 14.1158 +	char pathfile[PLATFORM_MAX_PATH];
 14.1159 +
 14.1160 +	for (uint32_t i=0; i<num; i++)
 14.1161 +	{
 14.1162 +		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 14.1163 +		{
 14.1164 +			continue;
 14.1165 +		}
 14.1166 +		if (strncmp(pubvar->name, "__pl_", 5) == 0)
 14.1167 +		{
 14.1168 +			pl = (_pl *)pubvar->offs;
 14.1169 +			if (pBase->LocalToString(pl->file, &file) != SP_ERROR_NONE)
 14.1170 +			{
 14.1171 +				continue;
 14.1172 +			}
 14.1173 +			if (pBase->LocalToString(pl->name, &name) != SP_ERROR_NONE)
 14.1174 +			{
 14.1175 +				continue;
 14.1176 +			}
 14.1177 +			g_LibSys.GetFileFromPath(pathfile, sizeof(pathfile), pPlugin->GetFilename());
 14.1178 +			if (strcmp(pathfile, file) == 0)
 14.1179 +			{
 14.1180 +				continue;
 14.1181 +			}
 14.1182 +			if (pl->required == false)
 14.1183 +			{
 14.1184 +				IPluginFunction *pFunc;
 14.1185 +				char buffer[64];
 14.1186 +				UTIL_Format(buffer, sizeof(buffer), "__pl_%s_SetNTVOptional", &pubvar->name[5]);
 14.1187 +				if ((pFunc=pBase->GetFunctionByName(buffer)))
 14.1188 +				{
 14.1189 +					cell_t res;
 14.1190 +					pFunc->Execute(&res);
 14.1191 +					if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
 14.1192 +					{
 14.1193 +						if (error)
 14.1194 +						{
 14.1195 +							snprintf(error, maxlength, "Fatal error during initializing plugin load");
 14.1196 +						}
 14.1197 +						return false;
 14.1198 +					}
 14.1199 +				}
 14.1200 +			}
 14.1201 +			else
 14.1202 +			{
 14.1203 +				/* Check that we aren't registering the same library twice */
 14.1204 +				if (pPlugin->m_RequiredLibs.find(name) == pPlugin->m_RequiredLibs.end())
 14.1205 +				{
 14.1206 +					pPlugin->m_RequiredLibs.push_back(name);
 14.1207 +				}
 14.1208 +				else
 14.1209 +				{
 14.1210 +					continue;
 14.1211 +				}
 14.1212 +				List<CPlugin *>::iterator iter;
 14.1213 +				CPlugin *pl;
 14.1214 +				bool found = false;
 14.1215 +				for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 14.1216 +				{
 14.1217 +					pl = (*iter);
 14.1218 +					if (pl->m_Libraries.find(name) != pl->m_Libraries.end())
 14.1219 +					{
 14.1220 +						found = true;
 14.1221 +						break;
 14.1222 +					}
 14.1223 +				}
 14.1224 +				if (!found)
 14.1225 +				{
 14.1226 +					if (error)
 14.1227 +					{
 14.1228 +						snprintf(error, maxlength, "Could not find required plugin \"%s\"", name);
 14.1229 +					}
 14.1230 +					return false;
 14.1231 +				}
 14.1232 +			}
 14.1233 +		}
 14.1234 +	}
 14.1235 +
 14.1236 +	return true;
 14.1237 +}
 14.1238 +
 14.1239 +bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
 14.1240 +{
 14.1241 +	/* Find any extensions this plugin needs */
 14.1242 +	struct _ext
 14.1243 +	{
 14.1244 +		cell_t name;
 14.1245 +		cell_t file;
 14.1246 +		cell_t autoload;
 14.1247 +		cell_t required;
 14.1248 +	} *ext;
 14.1249 +
 14.1250 +	IPluginContext *pBase = pPlugin->GetBaseContext();
 14.1251 +	uint32_t num = pBase->GetPubVarsNum();
 14.1252 +	sp_pubvar_t *pubvar;
 14.1253 +	IExtension *pExt;
 14.1254 +	char path[PLATFORM_MAX_PATH];
 14.1255 +	char *file, *name;
 14.1256 +	for (uint32_t i=0; i<num; i++)
 14.1257 +	{
 14.1258 +		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 14.1259 +		{
 14.1260 +			continue;
 14.1261 +		}
 14.1262 +		if (strncmp(pubvar->name, "__ext_", 6) == 0)
 14.1263 +		{
 14.1264 +			ext = (_ext *)pubvar->offs;
 14.1265 +			if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
 14.1266 +			{
 14.1267 +				continue;
 14.1268 +			}
 14.1269 +			if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
 14.1270 +			{
 14.1271 +				continue;
 14.1272 +			}
 14.1273 +			if (pass == 1)
 14.1274 +			{
 14.1275 +				/* Attempt to auto-load if necessary */
 14.1276 +				if (ext->autoload)
 14.1277 +				{
 14.1278 +					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
 14.1279 +					g_Extensions.LoadAutoExtension(path);
 14.1280 +				}
 14.1281 +			}
 14.1282 +			else if (pass == 2)
 14.1283 +			{
 14.1284 +				/* Is this required? */
 14.1285 +				if (ext->required)
 14.1286 +				{
 14.1287 +					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
 14.1288 +					if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
 14.1289 +					{
 14.1290 +						pExt = g_Extensions.FindExtensionByName(name);
 14.1291 +					}
 14.1292 +					/* :TODO: should we bind to unloaded extensions?
 14.1293 +					 * Currently the extension manager will ignore this.
 14.1294 +					 */
 14.1295 +					if (!pExt || !pExt->IsRunning(NULL, 0))
 14.1296 +					{
 14.1297 +						if (error)
 14.1298 +						{
 14.1299 +							snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
 14.1300 +						}
 14.1301 +						return false;
 14.1302 +					}
 14.1303 +					else
 14.1304 +					{
 14.1305 +						g_Extensions.BindChildPlugin(pExt, pPlugin);
 14.1306 +					}
 14.1307 +				}
 14.1308 +				else
 14.1309 +				{
 14.1310 +					IPluginFunction *pFunc;
 14.1311 +					char buffer[64];
 14.1312 +					UTIL_Format(buffer, sizeof(buffer), "__ext_%s_SetNTVOptional", &pubvar->name[6]);
 14.1313 +
 14.1314 +					if ((pFunc = pBase->GetFunctionByName(buffer)) != NULL)
 14.1315 +					{
 14.1316 +						cell_t res;
 14.1317 +						pFunc->Execute(&res);
 14.1318 +						if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
 14.1319 +						{
 14.1320 +							if (error)
 14.1321 +							{
 14.1322 +								UTIL_Format(error, maxlength, "Fatal error during plugin initialization (ext req)");
 14.1323 +							}
 14.1324 +							return false;
 14.1325 +						}
 14.1326 +					}
 14.1327 +				}
 14.1328 +			}
 14.1329 +		}
 14.1330 +	}
 14.1331 +
 14.1332 +	return true;
 14.1333 +}
 14.1334 +
 14.1335 +bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
 14.1336 +{
 14.1337 +	/* Second pass for extension requirements */
 14.1338 +	if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
 14.1339 +	{
 14.1340 +		return false;
 14.1341 +	}
 14.1342 +
 14.1343 +	if (!FindOrRequirePluginDeps(pPlugin, error, maxlength))
 14.1344 +	{
 14.1345 +		return false;
 14.1346 +	}
 14.1347 +
 14.1348 +	/* Run another binding pass */
 14.1349 +	g_ShareSys.BindNativesToPlugin(pPlugin, false);
 14.1350 +
 14.1351 +	/* Find any unbound natives. Right now, these are not allowed. */
 14.1352 +	IPluginContext *pContext = pPlugin->GetBaseContext();
 14.1353 +	uint32_t num = pContext->GetNativesNum();
 14.1354 +	sp_native_t *native;
 14.1355 +	for (unsigned int i=0; i<num; i++)
 14.1356 +	{
 14.1357 +		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
 14.1358 +		{
 14.1359 +			break;
 14.1360 +		}
 14.1361 +		if (native->status == SP_NATIVE_UNBOUND
 14.1362 +			&& native->name[0] != '@'
 14.1363 +			&& !(native->flags & SP_NTVFLAG_OPTIONAL))
 14.1364 +		{
 14.1365 +			if (error)
 14.1366 +			{
 14.1367 +				snprintf(error, maxlength, "Native \"%s\" was not found", native->name);
 14.1368 +			}
 14.1369 +			return false;
 14.1370 +		}
 14.1371 +	}
 14.1372 +
 14.1373 +	/* Finish by telling all listeners */
 14.1374 +	List<IPluginsListener *>::iterator iter;
 14.1375 +	IPluginsListener *pListener;
 14.1376 +	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 14.1377 +	{
 14.1378 +		pListener = (*iter);
 14.1379 +		pListener->OnPluginLoaded(pPlugin);
 14.1380 +	}
 14.1381 +	
 14.1382 +	/* Tell this plugin to finish initializing itself */
 14.1383 +	pPlugin->Call_OnPluginStart();
 14.1384 +
 14.1385 +	/* Now, if we have fake natives, go through all plugins that might need rebinding */
 14.1386 +	if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_Natives.size())
 14.1387 +	{
 14.1388 +		List<CPlugin *>::iterator pl_iter;
 14.1389 +		CPlugin *pOther;
 14.1390 +		for (pl_iter = m_plugins.begin();
 14.1391 +			 pl_iter != m_plugins.end();
 14.1392 +			 pl_iter++)
 14.1393 +		{
 14.1394 +			pOther = (*pl_iter);
 14.1395 +			if ((pOther->GetStatus() == Plugin_Error
 14.1396 +				&& (pOther->m_FakeNativesMissing || pOther->m_LibraryMissing))
 14.1397 +				|| pOther->m_FakeNativesMissing)
 14.1398 +			{
 14.1399 +				TryRefreshDependencies(pOther);
 14.1400 +			}
 14.1401 +			else if ((pOther->GetStatus() == Plugin_Running
 14.1402 +					  || pOther->GetStatus() == Plugin_Paused)
 14.1403 +					 && pOther != pPlugin)
 14.1404 +			{
 14.1405 +				List<NativeEntry *>::iterator nv_iter;
 14.1406 +				for (nv_iter = pPlugin->m_Natives.begin();
 14.1407 +					 nv_iter != pPlugin->m_Natives.end();
 14.1408 +					 nv_iter++)
 14.1409 +				{
 14.1410 +					g_ShareSys.BindNativeToPlugin(pOther, (*nv_iter));
 14.1411 +				}
 14.1412 +			}
 14.1413 +		}
 14.1414 +	}
 14.1415 +
 14.1416 +	/* Go through our libraries and tell other plugins they're added */
 14.1417 +	List<String>::iterator s_iter;
 14.1418 +	for (s_iter = pPlugin->m_Libraries.begin();
 14.1419 +		s_iter != pPlugin->m_Libraries.end();
 14.1420 +		s_iter++)
 14.1421 +	{
 14.1422 +		OnLibraryAction((*s_iter).c_str(), true, false);
 14.1423 +	}
 14.1424 +
 14.1425 +	/* :TODO: optimize? does this even matter? */
 14.1426 +	pPlugin->GetPhrases()->AddPhraseFile("core.phrases");
 14.1427 +
 14.1428 +	return true;
 14.1429 +}
 14.1430 +
 14.1431 +void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
 14.1432 +{
 14.1433 +	assert(pPlugin->GetBaseContext() != NULL);
 14.1434 +
 14.1435 +	g_ShareSys.BindNativesToPlugin(pPlugin, false);
 14.1436 +
 14.1437 +	List<String>::iterator lib_iter;
 14.1438 +	List<String>::iterator req_iter;
 14.1439 +	List<CPlugin *>::iterator pl_iter;
 14.1440 +	CPlugin *pl;
 14.1441 +	for (req_iter=pPlugin->m_RequiredLibs.begin(); req_iter!=pPlugin->m_RequiredLibs.end(); req_iter++)
 14.1442 +	{
 14.1443 +		bool found = false;
 14.1444 +		for (pl_iter=m_plugins.begin(); pl_iter!=m_plugins.end(); pl_iter++)
 14.1445 +		{
 14.1446 +			pl = (*pl_iter);
 14.1447 +			for (lib_iter=pl->m_Libraries.begin(); lib_iter!=pl->m_Libraries.end(); lib_iter++)
 14.1448 +			{
 14.1449 +				if ((*req_iter) == (*lib_iter))
 14.1450 +				{
 14.1451 +					found = true;
 14.1452 +				}
 14.1453 +			}
 14.1454 +		}
 14.1455 +		if (!found)
 14.1456 +		{
 14.1457 +			pPlugin->SetErrorState(Plugin_Error, "Library not found: %s", (*req_iter).c_str());
 14.1458 +			return;
 14.1459 +		}
 14.1460 +	}
 14.1461 +
 14.1462 +	/* Find any unbound natives
 14.1463 +	 * Right now, these are not allowed
 14.1464 +	 */
 14.1465 +	IPluginContext *pContext = pPlugin->GetBaseContext();
 14.1466 +	uint32_t num = pContext->GetNativesNum();
 14.1467 +	sp_native_t *native;
 14.1468 +	for (unsigned int i=0; i<num; i++)
 14.1469 +	{
 14.1470 +		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
 14.1471 +		{
 14.1472 +			break;
 14.1473 +		}
 14.1474 +		if (native->status == SP_NATIVE_UNBOUND && !(native->flags & SP_NTVFLAG_OPTIONAL))
 14.1475 +		{
 14.1476 +			pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
 14.1477 +			return;
 14.1478 +		}
 14.1479 +	}
 14.1480 +
 14.1481 +	if (pPlugin->GetStatus() == Plugin_Error)
 14.1482 +	{
 14.1483 +		/* If we got here, all natives are okay again! */
 14.1484 +		pPlugin->m_status = Plugin_Running;
 14.1485 +		if (pPlugin->m_pRuntime->IsPaused())
 14.1486 +		{
 14.1487 +			pPlugin->m_pRuntime->SetPauseState(false);
 14.1488 +			_SetPauseState(pPlugin, false);
 14.1489 +		}
 14.1490 +	}
 14.1491 +}
 14.1492 +
 14.1493 +bool CPluginManager::UnloadPlugin(IPlugin *plugin)
 14.1494 +{
 14.1495 +	CPlugin *pPlugin = (CPlugin *)plugin;
 14.1496 +
 14.1497 +	/* This prevents removal during insertion or anything else weird */
 14.1498 +	if (m_plugins.find(pPlugin) == m_plugins.end())
 14.1499 +	{
 14.1500 +		return false;
 14.1501 +	}
 14.1502 +
 14.1503 +	IPluginContext *pContext = plugin->GetBaseContext();
 14.1504 +	if (pContext != NULL && pContext->IsInExec())
 14.1505 +	{
 14.1506 +		char buffer[255];
 14.1507 +		UTIL_Format(buffer, sizeof(buffer), "sm plugins unload %s\n", plugin->GetFilename());
 14.1508 +		engine->ServerCommand(buffer);
 14.1509 +		return false;
 14.1510 +	}
 14.1511 +
 14.1512 +	/* Remove us from the lookup table and linked list */
 14.1513 +	m_plugins.remove(pPlugin);
 14.1514 +	sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
 14.1515 +
 14.1516 +	/* Go through our libraries and tell other plugins they're gone */
 14.1517 +	List<String>::iterator s_iter;
 14.1518 +	for (s_iter = pPlugin->m_Libraries.begin();
 14.1519 +		 s_iter != pPlugin->m_Libraries.end();
 14.1520 +		 s_iter++)
 14.1521 +	{
 14.1522 +		OnLibraryAction((*s_iter).c_str(), true, true);
 14.1523 +	}
 14.1524 +
 14.1525 +	List<IPluginsListener *>::iterator iter;
 14.1526 +	IPluginsListener *pListener;
 14.1527 +
 14.1528 +	if (pPlugin->GetStatus() <= Plugin_Error)
 14.1529 +	{
 14.1530 +		/* Notify listeners of unloading */
 14.1531 +		for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 14.1532 +		{
 14.1533 +			pListener = (*iter);
 14.1534 +			pListener->OnPluginUnloaded(pPlugin);
 14.1535 +		}
 14.1536 +		/* Notify plugin */
 14.1537 +		pPlugin->Call_OnPluginEnd();
 14.1538 +	}
 14.1539 +
 14.1540 +	pPlugin->DropEverything();
 14.1541 +
 14.1542 +	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 14.1543 +	{
 14.1544 +		/* Notify listeners of destruction */
 14.1545 +		pListener = (*iter);
 14.1546 +		pListener->OnPluginDestroyed(pPlugin);
 14.1547 +	}
 14.1548 +	
 14.1549 +	/* Tell the plugin to delete itself */
 14.1550 +	delete pPlugin;
 14.1551 +
 14.1552 +	return true;
 14.1553 +}
 14.1554 +
 14.1555 +IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
 14.1556 +{
 14.1557 +	IPlugin *pPlugin;
 14.1558 +	IPluginContext *pContext;
 14.1559 +
 14.1560 +	pContext = reinterpret_cast<IPluginContext *>(const_cast<sp_context_t *>(ctx));
 14.1561 +
 14.1562 +	if (pContext->GetKey(2, (void **)&pPlugin))
 14.1563 +	{
 14.1564 +		return pPlugin;
 14.1565 +	}
 14.1566 +
 14.1567 +	return NULL;
 14.1568 +}
 14.1569 +
 14.1570 +CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
 14.1571 +{
 14.1572 +	return (CPlugin *)FindPluginByContext(ctx);
 14.1573 +}
 14.1574 +
 14.1575 +unsigned int CPluginManager::GetPluginCount()
 14.1576 +{
 14.1577 +	return m_plugins.size();
 14.1578 +}
 14.1579 +
 14.1580 +void CPluginManager::AddPluginsListener(IPluginsListener *listener)
 14.1581 +{
 14.1582 +	m_listeners.push_back(listener);
 14.1583 +}
 14.1584 +
 14.1585 +void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
 14.1586 +{
 14.1587 +	m_listeners.remove(listener);
 14.1588 +}
 14.1589 +
 14.1590 +IPluginIterator *CPluginManager::GetPluginIterator()
 14.1591 +{
 14.1592 +	if (m_iters.empty())
 14.1593 +	{
 14.1594 +		return new CPluginIterator(&m_plugins);
 14.1595 +	} else {
 14.1596 +		CPluginIterator *iter = m_iters.front();
 14.1597 +		m_iters.pop();
 14.1598 +		iter->Reset();
 14.1599 +		return iter;
 14.1600 +	}
 14.1601 +}
 14.1602 +
 14.1603 +void CPluginManager::ReleaseIterator(CPluginIterator *iter)
 14.1604 +{
 14.1605 +	m_iters.push(iter);
 14.1606 +}
 14.1607 +
 14.1608 +bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
 14.1609 +{
 14.1610 +	/* As an optimization, we do not call strlen, but compute the length in the first pass */
 14.1611 +	size_t alias_len = 0;
 14.1612 +	size_t local_len = 0;
 14.1613 +
 14.1614 +	const char *ptr = alias;
 14.1615 +	unsigned int alias_explicit_paths = 0;
 14.1616 +	unsigned int alias_path_end = 0;
 14.1617 +	while (*ptr != '\0')
 14.1618 +	{
 14.1619 +		if (*ptr == '\\' || *ptr == '/')
 14.1620 +		{
 14.1621 +			alias_explicit_paths++;
 14.1622 +			alias_path_end = alias_len;
 14.1623 +		}
 14.1624 +		alias_len++;
 14.1625 +		ptr++;
 14.1626 +	}
 14.1627 +
 14.1628 +	if (alias_explicit_paths && alias_path_end == alias_len - 1)
 14.1629 +	{
 14.1630 +		/* Trailing slash is totally invalid here */
 14.1631 +		return false;
 14.1632 +	}
 14.1633 +
 14.1634 +	ptr = localpath;
 14.1635 +	unsigned int local_explicit_paths = 0;
 14.1636 +	unsigned int local_path_end = 0;
 14.1637 +	while (*ptr != '\0')
 14.1638 +	{
 14.1639 +		if (*ptr == '\\' || *ptr == '/')
 14.1640 +		{
 14.1641 +			local_explicit_paths++;
 14.1642 +			local_path_end = local_len;
 14.1643 +		}
 14.1644 +		local_len++;
 14.1645 +		ptr++;
 14.1646 +	}
 14.1647 +
 14.1648 +	/* If the alias has more explicit paths than the real path,
 14.1649 +	 * no match will be possible.
 14.1650 +	 */
 14.1651 +	if (alias_explicit_paths > local_explicit_paths)
 14.1652 +	{
 14.1653 +		return false;
 14.1654 +	}
 14.1655 +
 14.1656 +	if (alias_explicit_paths)
 14.1657 +	{
 14.1658 +		/* We need to find if the paths match now.  For example, these should all match:
 14.1659 +		 * csdm     csdm
 14.1660 +		 * csdm     optional/csdm
 14.1661 +		 * csdm/ban optional/crab/csdm/ban
 14.1662 +		*/
 14.1663 +		const char *aliasptr = alias;
 14.1664 +		const char *localptr = localpath;
 14.1665 +		bool match = true;
 14.1666 +		do
 14.1667 +		{
 14.1668 +			if (*aliasptr != *localptr)
 14.1669 +			{
 14.1670 +				/* We have to knock one path off */
 14.1671 +				local_explicit_paths--;
 14.1672 +				if (alias_explicit_paths > local_explicit_paths)
 14.1673 +				{
 14.1674 +					/* Skip out if we're gonna have an impossible match */
 14.1675 +					return false;
 14.1676 +				}
 14.1677 +				/* Eat up localptr tokens until we get a result */
 14.1678 +				while (((localptr - localpath) < (int)local_path_end)
 14.1679 +					&& *localptr != '/'
 14.1680 +					&& *localptr != '\\')
 14.1681 +				{
 14.1682 +					localptr++;
 14.1683 +				}
 14.1684 +				/* Check if we hit the end of our searchable area.
 14.1685 +				 * This probably isn't possible because of the path 
 14.1686 +				 * count check, but it's a good idea anyway.
 14.1687 +				 */
 14.1688 +				if ((localptr - localpath) >= (int)local_path_end)
 14.1689 +				{
 14.1690 +					return false;
 14.1691 +				} else {
 14.1692 +					/* Consume the slash token */
 14.1693 +					localptr++;
 14.1694 +				}
 14.1695 +				/* Reset the alias pointer so we can continue consuming */
 14.1696 +				aliasptr = alias;
 14.1697 +				match = false;
 14.1698 +				continue;
 14.1699 +			}
 14.1700 +			/* Note:
 14.1701 +			 * This is safe because if localptr terminates early, aliasptr will too
 14.1702 +			 */
 14.1703 +			do
 14.1704 +			{
 14.1705 +				/* We should never reach the end of the string because of this check. */
 14.1706 +				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
 14.1707 +				bool localend = (localptr - localpath) > (int)local_path_end;
 14.1708 +				if (aliasend || localend)
 14.1709 +				{
 14.1710 +					if (aliasend && localend)
 14.1711 +					{
 14.1712 +						/* we matched, and we can break out now */
 14.1713 +						match = true;
 14.1714 +						break;
 14.1715 +					}
 14.1716 +					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
 14.1717 +					match = false;
 14.1718 +					break;
 14.1719 +				}
 14.1720 +
 14.1721 +				/* If we got here, it's safe to compare the next two tokens */
 14.1722 +				if (*localptr != *aliasptr)
 14.1723 +				{
 14.1724 +					match = false;
 14.1725 +					break;
 14.1726 +				}
 14.1727 +				localptr++;
 14.1728 +				aliasptr++;
 14.1729 +			} while (true);
 14.1730 +		} while (!match);
 14.1731 +	}
 14.1732 +
 14.1733 +	/* If we got here, it's time to compare filenames */
 14.1734 +	const char *aliasptr = alias;
 14.1735 +	const char *localptr = localpath;
 14.1736 +
 14.1737 +	if (alias_explicit_paths)
 14.1738 +	{
 14.1739 +		aliasptr = &alias[alias_path_end + 1];
 14.1740 +	}
 14.1741 +
 14.1742 +	if (local_explicit_paths)
 14.1743 +	{
 14.1744 +		localptr = &localpath[local_path_end + 1];
 14.1745 +	}
 14.1746 +
 14.1747 +	while (true)
 14.1748 +	{
 14.1749 +		if (*aliasptr == '*')
 14.1750 +		{
 14.1751 +			/* First, see if this is the last character */
 14.1752 +			if ((unsigned)(aliasptr - alias) == alias_len - 1)
 14.1753 +			{
 14.1754 +				/* If so, there's no need to match anything else */
 14.1755 +				return true;
 14.1756 +			}
 14.1757 +			/* Otherwise, we need to search for an appropriate matching sequence in local.
 14.1758 +			 * Note that we only need to search up to the next asterisk.
 14.1759 +			 */
 14.1760 +			aliasptr++;
 14.1761 +			bool match = true;
 14.1762 +			const char *local_orig = localptr;
 14.1763 +			do
 14.1764 +			{
 14.1765 +				match = true;
 14.1766 +				while (*aliasptr != '\0' && *aliasptr != '*')
 14.1767 +				{
 14.1768 +					/* Since aliasptr is never '\0', localptr hitting the end will fail */
 14.1769 +					if (*aliasptr != *localptr)
 14.1770 +					{
 14.1771 +						match = false;
 14.1772 +						break;
 14.1773 +					}
 14.1774 +					aliasptr++;
 14.1775 +					localptr++;
 14.1776 +				}
 14.1777 +				if (!match)
 14.1778 +				{
 14.1779 +					/* If we didn't get a match, we need to advance the search stream.
 14.1780 +					 * This will let us skip tokens while still searching for another match.
 14.1781 +					 */
 14.1782 +					localptr = ++local_orig;
 14.1783 +					/* Make sure we don't go out of bounds */
 14.1784 +					if (*localptr == '\0')
 14.1785 +					{
 14.1786 +						break;
 14.1787 +					}
 14.1788 +				}
 14.1789 +			} while (!match);
 14.1790 +
 14.1791 +			if (!match)
 14.1792 +			{
 14.1793 +				return false;
 14.1794 +			} else {
 14.1795 +				/* If we got a match, move on to the next token */
 14.1796 +				continue;
 14.1797 +			}
 14.1798 +		} else if (*aliasptr == '\0') {
 14.1799 +			if (*localptr == '\0'
 14.1800 +				||
 14.1801 +				strcmp(localptr, ".smx") == 0)
 14.1802 +			{
 14.1803 +				return true;
 14.1804 +			} else {
 14.1805 +				return false;
 14.1806 +			}
 14.1807 +		} else if (*aliasptr != *localptr) {
 14.1808 +			return false;
 14.1809 +		}
 14.1810 +		aliasptr++;
 14.1811 +		localptr++;
 14.1812 +	}
 14.1813 +
 14.1814 +	return true;
 14.1815 +}
 14.1816 +
 14.1817 +bool CPluginManager::IsLateLoadTime() const
 14.1818 +{
 14.1819 +	return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
 14.1820 +}
 14.1821 +
 14.1822 +void CPluginManager::OnSourceModAllInitialized()
 14.1823 +{
 14.1824 +	m_MyIdent = g_ShareSys.CreateCoreIdentity();
 14.1825 +
 14.1826 +	HandleAccess sec;
 14.1827 +	g_HandleSys.InitAccessDefaults(NULL, &sec);
 14.1828 +
 14.1829 +	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
 14.1830 +	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
 14.1831 +
 14.1832 +	g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
 14.1833 +	g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
 14.1834 +
 14.1835 +	g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
 14.1836 +
 14.1837 +	g_ShareSys.AddInterface(NULL, this);
 14.1838 +}
 14.1839 +
 14.1840 +void CPluginManager::OnSourceModShutdown()
 14.1841 +{
 14.1842 +	g_RootMenu.RemoveRootConsoleCommand("plugins", this);
 14.1843 +
 14.1844 +	UnloadAll();
 14.1845 +
 14.1846 +	g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
 14.1847 +	g_ShareSys.DestroyIdentType(g_PluginIdent);
 14.1848 +	g_ShareSys.DestroyIdentity(m_MyIdent);
 14.1849 +}
 14.1850 +
 14.1851 +void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
 14.1852 +{
 14.1853 +	/* We don't care about the internal object, actually */
 14.1854 +}
 14.1855 +
 14.1856 +bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
 14.1857 +{
 14.1858 +	*pSize = ((CPlugin *)object)->CalcMemUsage();
 14.1859 +	return true;
 14.1860 +}
 14.1861 +
 14.1862 +IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
 14.1863 +{
 14.1864 +	IPlugin *pPlugin;
 14.1865 +	HandleError _err;
 14.1866 +
 14.1867 +	HandleSecurity sec;
 14.1868 +
 14.1869 +	sec.pOwner = NULL;
 14.1870 +	sec.pIdentity = m_MyIdent;
 14.1871 +
 14.1872 +	if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
 14.1873 +	{
 14.1874 +		pPlugin = NULL;
 14.1875 +	}
 14.1876 +
 14.1877 +	if (err)
 14.1878 +	{
 14.1879 +		*err = _err;
 14.1880 +	}
 14.1881 +
 14.1882 +	return pPlugin;
 14.1883 +}
 14.1884 +
 14.1885 +CPlugin *CPluginManager::GetPluginByOrder(int num)
 14.1886 +{
 14.1887 +	if (num < 1 || num > (int)GetPluginCount())
 14.1888 +	{
 14.1889 +		return NULL;
 14.1890 +	}
 14.1891 +
 14.1892 +	CPlugin *pl;
 14.1893 +	int id = 1;
 14.1894 +
 14.1895 +	SourceHook::List<CPlugin *>::iterator iter;
 14.1896 +	for (iter = m_plugins.begin(); iter != m_plugins.end() && id < num; iter++, id++) {}
 14.1897 +
 14.1898 +	pl = *iter;
 14.1899 +
 14.1900 +	return pl;
 14.1901 +}
 14.1902 +
 14.1903 +const char *CPluginManager::GetStatusText(PluginStatus st)
 14.1904 +{
 14.1905 +	switch (st)
 14.1906 +	{
 14.1907 +	case Plugin_Running:
 14.1908 +		return "Running";
 14.1909 +	case Plugin_Paused:
 14.1910 +		return "Paused";
 14.1911 +	case Plugin_Error:
 14.1912 +		return "Error";
 14.1913 +	case Plugin_Uncompiled:
 14.1914 +		return "Uncompiled";
 14.1915 +	case Plugin_BadLoad:
 14.1916 +		return "Bad Load";
 14.1917 +	case Plugin_Failed:
 14.1918 +		return "Failed";
 14.1919 +	default:
 14.1920 +		assert(false);
 14.1921 +		return "-";
 14.1922 +	}
 14.1923 +}
 14.1924 +
 14.1925 +void CPluginManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
 14.1926 +{
 14.1927 +	int argcount = command.ArgC();
 14.1928 +	if (argcount >= 3)
 14.1929 +	{
 14.1930 +		const char *cmd = command.Arg(2);
 14.1931 +		if (strcmp(cmd, "list") == 0)
 14.1932 +		{
 14.1933 +			char buffer[256];
 14.1934 +			unsigned int id = 1;
 14.1935 +			int plnum = GetPluginCount();
 14.1936 +
 14.1937 +			if (!plnum)
 14.1938 +			{
 14.1939 +				g_RootMenu.ConsolePrint("[SM] No plugins loaded");
 14.1940 +				return;
 14.1941 +			}
 14.1942 +			else
 14.1943 +			{
 14.1944 +				g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
 14.1945 +			}
 14.1946 +
 14.1947 +			CPlugin *pl;
 14.1948 +			SourceHook::List<CPlugin *>::iterator iter;
 14.1949 +			SourceHook::List<CPlugin *> m_FailList;
 14.1950 +
 14.1951 +			for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
 14.1952 +			{
 14.1953 +				pl = (*iter);
 14.1954 +				assert(pl->GetStatus() != Plugin_Created);
 14.1955 +				int len = 0;
 14.1956 +				const sm_plugininfo_t *info = pl->GetPublicInfo();
 14.1957 +				if (pl->GetStatus() != Plugin_Running)
 14.1958 +				{
 14.1959 +					len += UTIL_Format(buffer, sizeof(buffer), "  %02d <%s>", id, GetStatusText(pl->GetStatus()));
 14.1960 +
 14.1961 +					if (pl->GetStatus() <= Plugin_Error)
 14.1962 +					{
 14.1963 +						/* Plugin has failed to load. */
 14.1964 +						m_FailList.push_back(pl);
 14.1965 +					}
 14.1966 +				}
 14.1967 +				else
 14.1968 +				{
 14.1969 +					len += UTIL_Format(buffer, sizeof(buffer), "  %02d", id);
 14.1970 +				}
 14.1971 +				if (pl->GetStatus() < Plugin_Created)
 14.1972 +				{
 14.1973 +					len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 14.1974 +					if (IS_STR_FILLED(info->version))
 14.1975 +					{
 14.1976 +						len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
 14.1977 +					}
 14.1978 +					if (IS_STR_FILLED(info->author))
 14.1979 +					{
 14.1980 +						UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
 14.1981 +					}
 14.1982 +				}
 14.1983 +				else
 14.1984 +				{
 14.1985 +					UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", pl->m_filename);
 14.1986 +				}
 14.1987 +				g_RootMenu.ConsolePrint("%s", buffer);
 14.1988 +			}
 14.1989 +
 14.1990 +			if (!m_FailList.empty())
 14.1991 +			{
 14.1992 +				g_RootMenu.ConsolePrint("Load Errors:");
 14.1993 +
 14.1994 +				SourceHook::List<CPlugin *>::iterator _iter;
 14.1995 +
 14.1996 +				CPlugin *pl;
 14.1997 +
 14.1998 +				for (_iter=m_FailList.begin(); _iter!=m_FailList.end(); _iter++)
 14.1999 +				{
 14.2000 +					pl = (CPlugin *)*_iter;
 14.2001 +					g_RootMenu.ConsolePrint("%s: %s",(IS_STR_FILLED(pl->GetPublicInfo()->name)) ? pl->GetPublicInfo()->name : pl->GetFilename(), pl->m_errormsg);
 14.2002 +				}
 14.2003 +			}
 14.2004 +
 14.2005 +			return;
 14.2006 +		}
 14.2007 +		else if (strcmp(cmd, "load") == 0)
 14.2008 +		{
 14.2009 +			if (argcount < 4)
 14.2010 +			{
 14.2011 +				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load <file>");
 14.2012 +				return;
 14.2013 +			}
 14.2014 +
 14.2015 +			char error[128];
 14.2016 +			bool wasloaded;
 14.2017 +			const char *filename = command.Arg(3);
 14.2018 +
 14.2019 +			char pluginfile[256];
 14.2020 +			const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx";
 14.2021 +			UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext);
 14.2022 +
 14.2023 +			IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded);
 14.2024 +
 14.2025 +			if (wasloaded)
 14.2026 +			{
 14.2027 +				g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile);
 14.2028 +				return;
 14.2029 +			}
 14.2030 +
 14.2031 +			if (pl)
 14.2032 +			{
 14.2033 +				g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile);
 14.2034 +			}
 14.2035 +			else
 14.2036 +			{
 14.2037 +				g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error);
 14.2038 +			}
 14.2039 +
 14.2040 +			return;
 14.2041 +		}
 14.2042 +		else if (strcmp(cmd, "unload") == 0)
 14.2043 +		{
 14.2044 +			if (argcount < 4)
 14.2045 +			{
 14.2046 +				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#|file>");
 14.2047 +				return;
 14.2048 +			}
 14.2049 +
 14.2050 +			CPlugin *pl;
 14.2051 +			char *end;
 14.2052 +			const char *arg = command.Arg(3);
 14.2053 +			int id = strtol(arg, &end, 10);
 14.2054 +
 14.2055 +			if (*end == '\0')
 14.2056 +			{
 14.2057 +				pl = GetPluginByOrder(id);
 14.2058 +				if (!pl)
 14.2059 +				{
 14.2060 +					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 14.2061 +					return;
 14.2062 +				}
 14.2063 +			}
 14.2064 +			else
 14.2065 +			{
 14.2066 +				char pluginfile[256];
 14.2067 +				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 14.2068 +				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 14.2069 +
 14.2070 +				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 14.2071 +				{
 14.2072 +					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 14.2073 +					return;
 14.2074 +				}
 14.2075 +			}
 14.2076 +
 14.2077 +			char name[PLATFORM_MAX_PATH];
 14.2078 +
 14.2079 +			if (pl->GetStatus() < Plugin_Created)
 14.2080 +			{
 14.2081 +				const sm_plugininfo_t *info = pl->GetPublicInfo();
 14.2082 +				UTIL_Format(name, sizeof(name), (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 14.2083 +			}
 14.2084 +			else
 14.2085 +			{
 14.2086 +				UTIL_Format(name, sizeof(name), "%s", pl->GetFilename());
 14.2087 +			}
 14.2088 +
 14.2089 +			if (UnloadPlugin(pl))
 14.2090 +			{
 14.2091 +				g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name);
 14.2092 +			}
 14.2093 +			else
 14.2094 +			{
 14.2095 +				g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name);
 14.2096 +			}
 14.2097 +
 14.2098 +			return;
 14.2099 +		}
 14.2100 +		else if (strcmp(cmd, "unload_all") == 0)
 14.2101 +		{
 14.2102 +			g_PluginSys.UnloadAll();
 14.2103 +			g_RootMenu.ConsolePrint("[SM] All plugins have been unloaded.");
 14.2104 +			return;
 14.2105 +		}
 14.2106 +		else if (strcmp(cmd, "load_lock") == 0)
 14.2107 +		{
 14.2108 +			if (m_LoadingLocked)
 14.2109 +			{
 14.2110 +				g_RootMenu.ConsolePrint("[SM] There is already a loading lock in effect.");
 14.2111 +			}
 14.2112 +			else
 14.2113 +			{
 14.2114 +				m_LoadingLocked = true;
 14.2115 +				g_RootMenu.ConsolePrint("[SM] Loading is now locked; no plugins will be loaded or re-loaded.");
 14.2116 +			}
 14.2117 +			return;
 14.2118 +		}
 14.2119 +		else if (strcmp(cmd, "load_unlock") == 0)
 14.2120 +		{
 14.2121 +			if (m_LoadingLocked)
 14.2122 +			{
 14.2123 +				m_LoadingLocked = false;
 14.2124 +				g_RootMenu.ConsolePrint("[SM] The loading lock is no longer in effect.");
 14.2125 +			}
 14.2126 +			else
 14.2127 +			{
 14.2128 +				g_RootMenu.ConsolePrint("[SM] There was no loading lock in effect.");
 14.2129 +			}
 14.2130 +			return;
 14.2131 +		}
 14.2132 +		else if (strcmp(cmd, "info") == 0)
 14.2133 +		{
 14.2134 +			if (argcount < 4)
 14.2135 +			{
 14.2136 +				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>");
 14.2137 +				return;
 14.2138 +			}
 14.2139 +
 14.2140 +			CPlugin *pl;
 14.2141 +			char *end;
 14.2142 +			const char *arg = command.Arg(3);
 14.2143 +			int id = strtol(arg, &end, 10);
 14.2144 +
 14.2145 +			if (*end == '\0')
 14.2146 +			{
 14.2147 +				pl = GetPluginByOrder(id);
 14.2148 +				if (!pl)
 14.2149 +				{
 14.2150 +					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 14.2151 +					return;
 14.2152 +				}
 14.2153 +			}
 14.2154 +			else
 14.2155 +			{
 14.2156 +				char pluginfile[256];
 14.2157 +				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 14.2158 +				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 14.2159 +
 14.2160 +				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 14.2161 +				{
 14.2162 +					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 14.2163 +					return;
 14.2164 +				}
 14.2165 +			}
 14.2166 +
 14.2167 +			const sm_plugininfo_t *info = pl->GetPublicInfo();
 14.2168 +
 14.2169 +			g_RootMenu.ConsolePrint("  Filename: %s", pl->GetFilename());
 14.2170 +			if (pl->GetStatus() <= Plugin_Error)
 14.2171 +			{
 14.2172 +				if (IS_STR_FILLED(info->name))
 14.2173 +				{
 14.2174 +					if (IS_STR_FILLED(info->description))
 14.2175 +					{
 14.2176 +						g_RootMenu.ConsolePrint("  Title: %s (%s)", info->name, info->description);
 14.2177 +					} else {
 14.2178 +						g_RootMenu.ConsolePrint("  Title: %s", info->name);
 14.2179 +					}
 14.2180 +				}
 14.2181 +				if (IS_STR_FILLED(info->author))
 14.2182 +				{
 14.2183 +					g_RootMenu.ConsolePrint("  Author: %s", info->author);
 14.2184 +				}
 14.2185 +				if (IS_STR_FILLED(info->version))
 14.2186 +				{
 14.2187 +					g_RootMenu.ConsolePrint("  Version: %s", info->version);
 14.2188 +				}
 14.2189 +				if (IS_STR_FILLED(info->url))
 14.2190 +				{
 14.2191 +					g_RootMenu.ConsolePrint("  URL: %s", info->url);
 14.2192 +				}
 14.2193 +				if (pl->GetStatus() == Plugin_Error)
 14.2194 +				{
 14.2195 +					g_RootMenu.ConsolePrint("  Error: %s", pl->m_errormsg);
 14.2196 +				}
 14.2197 +				else
 14.2198 +				{
 14.2199 +					if (pl->GetStatus() == Plugin_Running)
 14.2200 +					{
 14.2201 +						g_RootMenu.ConsolePrint("  Status: running");
 14.2202 +					}
 14.2203 +					else
 14.2204 +					{
 14.2205 +						g_RootMenu.ConsolePrint("  Status: not running");
 14.2206 +					}
 14.2207 +
 14.2208 +					const char *typestr = "";
 14.2209 +					switch (pl->GetType())
 14.2210 +					{
 14.2211 +					case PluginType_MapUpdated:
 14.2212 +						typestr = "Map Change if Updated";
 14.2213 +						break;
 14.2214 +					case PluginType_MapOnly:
 14.2215 +						typestr = "Map Change";
 14.2216 +						break;
 14.2217 +					case PluginType_Private:
 14.2218 +					case PluginType_Global:
 14.2219 +						typestr = "Never";
 14.2220 +						break;
 14.2221 +					}
 14.2222 +
 14.2223 +					g_RootMenu.ConsolePrint("  Reloads: %s", typestr);
 14.2224 +				}
 14.2225 +				if (pl->m_FileVersion >= 3)
 14.2226 +				{
 14.2227 +					g_RootMenu.ConsolePrint("  Timestamp: %s", pl->m_DateTime);
 14.2228 +				}
 14.2229 +			}
 14.2230 +			else
 14.2231 +			{
 14.2232 +				g_RootMenu.ConsolePrint("  Load error: %s", pl->m_errormsg);
 14.2233 +				if (pl->GetStatus() < Plugin_Created)
 14.2234 +				{
 14.2235 +					g_RootMenu.ConsolePrint("  File info: (title \"%s\") (version \"%s\")", 
 14.2236 +											info->name ? info->name : "<none>",
 14.2237 +											info->version ? info->version : "<none>");
 14.2238 +					if (IS_STR_FILLED(info->url))
 14.2239 +					{
 14.2240 +						g_RootMenu.ConsolePrint("  File URL: %s", info->url);
 14.2241 +					}
 14.2242 +				}
 14.2243 +			}
 14.2244 +
 14.2245 +			return;
 14.2246 +		}
 14.2247 +		else if (strcmp(cmd, "refresh") == 0)
 14.2248 +		{
 14.2249 +			g_SourceMod.DoGlobalPluginLoads();
 14.2250 +			g_RootMenu.ConsolePrint("[SM] The plugin list has been refreshed and reloaded.");
 14.2251 +			return;
 14.2252 +		}
 14.2253 +		else if (strcmp(cmd, "reload") == 0)
 14.2254 +		{
 14.2255 +			if (argcount < 4)
 14.2256 +			{
 14.2257 +				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins reload <#|file>");
 14.2258 +				return;
 14.2259 +			}
 14.2260 +
 14.2261 +			CPlugin *pl;
 14.2262 +			char *end;
 14.2263 +			const char *arg = command.Arg(3);
 14.2264 +			int id = strtol(arg, &end, 10);
 14.2265 +
 14.2266 +			if (*end == '\0')
 14.2267 +			{
 14.2268 +				pl = GetPluginByOrder(id);
 14.2269 +				if (!pl)
 14.2270 +				{
 14.2271 +					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 14.2272 +					return;
 14.2273 +				}
 14.2274 +			}
 14.2275 +			else
 14.2276 +			{
 14.2277 +				char pluginfile[256];
 14.2278 +				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 14.2279 +				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 14.2280 +
 14.2281 +				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 14.2282 +				{
 14.2283 +					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 14.2284 +					return;
 14.2285 +				}
 14.2286 +			}
 14.2287 +
 14.2288 +			char name[PLATFORM_MAX_PATH];
 14.2289 +			const sm_plugininfo_t *info = pl->GetPublicInfo();
 14.2290 +			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 14.2291 +
 14.2292 +			if (ReloadPlugin(pl))
 14.2293 +			{
 14.2294 +				g_RootMenu.ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
 14.2295 +			}
 14.2296 +			else
 14.2297 +			{
 14.2298 +				g_RootMenu.ConsolePrint("[SM] Failed to reload plugin %s.", name);
 14.2299 +			}
 14.2300 +
 14.2301 +			return;
 14.2302 +		}
 14.2303 +	}
 14.2304 +
 14.2305 +	/* Draw the main menu */
 14.2306 +	g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
 14.2307 +	g_RootMenu.DrawGenericOption("info", "Information about a plugin");
 14.2308 +	g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
 14.2309 +	g_RootMenu.DrawGenericOption("load", "Load a plugin");
 14.2310 +	g_RootMenu.DrawGenericOption("load_lock", "Prevents any more plugins from being loaded");
 14.2311 +	g_RootMenu.DrawGenericOption("load_unlock", "Re-enables plugin loading");
 14.2312 +	g_RootMenu.DrawGenericOption("refresh", "Reloads/refreshes all plugins in the plugins folder");
 14.2313 +	g_RootMenu.DrawGenericOption("reload", "Reloads a plugin");
 14.2314 +	g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
 14.2315 +	g_RootMenu.DrawGenericOption("unload_all", "Unloads all plugins");
 14.2316 +}
 14.2317 +
 14.2318 +bool CPluginManager::ReloadPlugin(CPlugin *pl)
 14.2319 +{
 14.2320 +	List<CPlugin *>::iterator iter;
 14.2321 +	char filename[PLATFORM_MAX_PATH];
 14.2322 +	bool wasloaded;
 14.2323 +	PluginType ptype;
 14.2324 +	IPlugin *newpl;
 14.2325 +	int id = 1;
 14.2326 +
 14.2327 +	strcpy(filename, pl->m_filename);
 14.2328 +	ptype = pl->GetType();
 14.2329 +
 14.2330 +	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++, id++)
 14.2331 +	{
 14.2332 +		if ((*iter) == pl)
 14.2333 +		{
 14.2334 +			break;
 14.2335 +		}
 14.2336 +	}
 14.2337 +
 14.2338 +	if (!UnloadPlugin(pl))
 14.2339 +	{
 14.2340 +		return false;
 14.2341 +	}
 14.2342 +	if (!(newpl=LoadPlugin(filename, true, ptype, NULL, 0, &wasloaded)))
 14.2343 +	{
 14.2344 +		return false;
 14.2345 +	}
 14.2346 +
 14.2347 +	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 14.2348 +	{
 14.2349 +		if ((*iter) == (CPlugin *)newpl)
 14.2350 +		{
 14.2351 +			m_plugins.erase(iter);
 14.2352 +			break;
 14.2353 +		}
 14.2354 +	}
 14.2355 +
 14.2356 +	int i;
 14.2357 +	for (i=1, iter=m_plugins.begin(); iter!=m_plugins.end() && i<id; iter++, i++)
 14.2358 +	{
 14.2359 +	}
 14.2360 +	m_plugins.insert(iter, (CPlugin *)newpl);
 14.2361 +
 14.2362 +	return true;
 14.2363 +}
 14.2364 +
 14.2365 +void CPluginManager::ReloadOrUnloadPlugins()
 14.2366 +{
 14.2367 +	/* If we're in a load lock, just skip this whole bit. */
 14.2368 +	if (m_LoadingLocked)
 14.2369 +	{
 14.2370 +		return;
 14.2371 +	}
 14.2372 +
 14.2373 +	List<CPlugin *>::iterator iter;
 14.2374 +	List<CPlugin *> tmp_list = m_plugins;
 14.2375 +	CPlugin *pl;
 14.2376 +	time_t t;
 14.2377 +
 14.2378 +	for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++)
 14.2379 +	{
 14.2380 +		pl = (*iter);
 14.2381 +		if (pl->GetType() ==  PluginType_MapOnly)
 14.2382 +		{
 14.2383 +			UnloadPlugin((IPlugin *)pl);
 14.2384 +		}
 14.2385 +		else if (pl->GetType() == PluginType_MapUpdated)
 14.2386 +		{
 14.2387 +			t = pl->GetFileTimeStamp();
 14.2388 +			if (!t || t > pl->GetTimeStamp())
 14.2389 +			{
 14.2390 +				pl->SetTimeStamp(t);
 14.2391 +				UnloadPlugin((IPlugin *)pl);
 14.2392 +			}
 14.2393 +		}
 14.2394 +	}
 14.2395 +}
 14.2396 +
 14.2397 +void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
 14.2398 +{
 14.2399 +	List<IPluginsListener *>::iterator iter;
 14.2400 +	IPluginsListener *pListener;
 14.2401 +	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 14.2402 +	{
 14.2403 +		pListener = (*iter);
 14.2404 +		pListener->OnPluginPauseChange(pl, paused);
 14.2405 +	}	
 14.2406 +}
 14.2407 +
 14.2408 +void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward)
 14.2409 +{
 14.2410 +	List<CPlugin *>::iterator iter;
 14.2411 +	CPlugin *pPlugin;
 14.2412 +	IPluginFunction *pFunction;
 14.2413 +
 14.2414 +	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
 14.2415 +	{
 14.2416 +		pPlugin = (*iter);
 14.2417 +
 14.2418 +		if (pPlugin->GetStatus() <= Plugin_Paused)
 14.2419 +		{
 14.2420 +			pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name);
 14.2421 +
 14.2422 +			if (pFunction)
 14.2423 +			{
 14.2424 +				pForward->AddFunction(pFunction);
 14.2425 +			}
 14.2426 +		}
 14.2427 +	}
 14.2428 +}
 14.2429 +
 14.2430 +CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken)
 14.2431 +{
 14.2432 +	if (pToken->type != g_PluginIdent)
 14.2433 +	{
 14.2434 +		return NULL;
 14.2435 +	}
 14.2436 +
 14.2437 +	return (CPlugin *)(pToken->ptr);
 14.2438 +}
 14.2439 +
 14.2440 +void CPluginManager::OnLibraryAction(const char *lib, bool is_a_plugin, bool drop)
 14.2441 +{
 14.2442 +	List<CPlugin *>::iterator iter;
 14.2443 +
 14.2444 +	struct _pl
 14.2445 +	{
 14.2446 +		cell_t name;
 14.2447 +		cell_t file;
 14.2448 +		cell_t required;
 14.2449 +	} *plc;
 14.2450 +
 14.2451 +	struct _ext
 14.2452 +	{
 14.2453 +		cell_t name;
 14.2454 +		cell_t file;
 14.2455 +		cell_t autoload;
 14.2456 +		cell_t required;
 14.2457 +	} *ext;
 14.2458 +
 14.2459 +	const char *name = drop ? "OnLibraryRemoved" : "OnLibraryAdded";
 14.2460 +
 14.2461 +	for (iter=m_plugins.begin();
 14.2462 +		 iter!=m_plugins.end();
 14.2463 +		 iter++)
 14.2464 +	{
 14.2465 +		CPlugin *pl = (*iter);
 14.2466 +		if (pl->GetStatus() != Plugin_Running)
 14.2467 +		{
 14.2468 +			continue;
 14.2469 +		}
 14.2470 +		IPluginContext *pContext = pl->GetBaseContext();
 14.2471 +		IPluginFunction *pf = pContext->GetFunctionByName(name);
 14.2472 +		if (!pf)
 14.2473 +		{
 14.2474 +			continue;
 14.2475 +		}
 14.2476 +		uint32_t num_vars = pContext->GetPubVarsNum();
 14.2477 +		for (uint32_t i=0; i<num_vars; i++)
 14.2478 +		{
 14.2479 +			sp_pubvar_t *pubvar;
 14.2480 +			if (pContext->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 14.2481 +			{
 14.2482 +				continue;
 14.2483 +			}
 14.2484 +			if (is_a_plugin && strncmp(pubvar->name, "__pl_", 5) == 0)
 14.2485 +			{
 14.2486 +				plc = (_pl *)pubvar->offs;
 14.2487 +				if (plc->required)
 14.2488 +				{
 14.2489 +					continue;
 14.2490 +				}
 14.2491 +				char *str;
 14.2492 +				pContext->LocalToString(plc->name, &str);
 14.2493 +				if (strcmp(str, lib) != 0)
 14.2494 +				{
 14.2495 +					continue;
 14.2496 +				}
 14.2497 +				pf->PushString(lib);
 14.2498 +				pf->Execute(NULL);
 14.2499 +			}
 14.2500 +			else if (!is_a_plugin && strncmp(pubvar->name, "__ext_", 6) == 0)
 14.2501 +			{
 14.2502 +				ext = (_ext *)pubvar->offs;
 14.2503 +				if (ext->required)
 14.2504 +				{
 14.2505 +					continue;
 14.2506 +				}
 14.2507 +				char *str;
 14.2508 +				pContext->LocalToString(ext->name, &str);
 14.2509 +				if (strcmp(str, lib) != 0)
 14.2510 +				{
 14.2511 +					continue;
 14.2512 +				}
 14.2513 +				pf->PushString(lib);
 14.2514 +				pf->Execute(NULL);
 14.2515 +			}
 14.2516 +		}
 14.2517 +	}
 14.2518 +}
 14.2519 +
 14.2520 +bool CPluginManager::LibraryExists(const char *lib)
 14.2521 +{
 14.2522 +	List<CPlugin *>::iterator iter;
 14.2523 +
 14.2524 +	for (iter=m_plugins.begin();
 14.2525 +		 iter!=m_plugins.end();
 14.2526 +		 iter++)
 14.2527 +	{
 14.2528 +		CPlugin *pl = (*iter);
 14.2529 +		if (pl->GetStatus() != Plugin_Running)
 14.2530 +		{
 14.2531 +			continue;
 14.2532 +		}
 14.2533 +		List<String>::iterator s_iter;
 14.2534 +		for (s_iter = pl->m_Libraries.begin();
 14.2535 +			 s_iter != pl->m_Libraries.end();
 14.2536 +			 s_iter++)
 14.2537 +		{
 14.2538 +			if ((*s_iter).compare(lib) == 0)
 14.2539 +			{
 14.2540 +				return true;
 14.2541 +			}
 14.2542 +		}
 14.2543 +	}
 14.2544 +
 14.2545 +	return false;
 14.2546 +}
 14.2547 +
 14.2548 +void CPluginManager::AllPluginsLoaded()
 14.2549 +{
 14.2550 +	List<CPlugin *>::iterator iter;
 14.2551 +	CPlugin *pl;
 14.2552 +
 14.2553 +	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 14.2554 +	{
 14.2555 +		pl = (*iter);
 14.2556 +		pl->Call_OnAllPluginsLoaded();
 14.2557 +	}
 14.2558 +}
 14.2559 +
 14.2560 +void CPluginManager::UnloadAll()
 14.2561 +{
 14.2562 +	List<CPlugin *>::iterator iter;
 14.2563 +	while ( (iter = m_plugins.begin()) != m_plugins.end() )
 14.2564 +	{
 14.2565 +		UnloadPlugin((*iter));
 14.2566 +	}
 14.2567 +}
 14.2568 +
 14.2569 +int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
 14.2570 +{
 14.2571 +	int id = 1;
 14.2572 +	List<CPlugin *>::iterator iter;
 14.2573 +
 14.2574 +	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
 14.2575 +	{
 14.2576 +		if ((*iter) == pl)
 14.2577 +		{
 14.2578 +			return id;
 14.2579 +		}
 14.2580 +	}
 14.2581 +
 14.2582 +	return -1;
 14.2583 +}
 14.2584 +
 14.2585 +CPlugin *CPluginManager::FindPluginByConsoleArg(const char *arg)
 14.2586 +{
 14.2587 +	int id;
 14.2588 +	char *end;
 14.2589 +	CPlugin *pl;
 14.2590 +	
 14.2591 +	id = strtol(arg, &end, 10);
 14.2592 +
 14.2593 +	if (*end == '\0')
 14.2594 +	{
 14.2595 +		pl = GetPluginByOrder(id);
 14.2596 +		if (!pl)
 14.2597 +		{
 14.2598 +			return NULL;
 14.2599 +		}
 14.2600 +	}
 14.2601 +	else
 14.2602 +	{
 14.2603 +		char pluginfile[256];
 14.2604 +		const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 14.2605 +		UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 14.2606 +
 14.2607 +		if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 14.2608 +		{
 14.2609 +			return NULL;
 14.2610 +		}
 14.2611 +	}
 14.2612 +
 14.2613 +	return pl;
 14.2614 +}
 14.2615 +
 14.2616 +void CPluginManager::OnSourceModMaxPlayersChanged(int newvalue)
 14.2617 +{
 14.2618 +	SyncMaxClients(newvalue);
 14.2619 +}
 14.2620 +
 14.2621 +void CPluginManager::SyncMaxClients(int max_clients)
 14.2622 +{
 14.2623 +	List<CPlugin *>::iterator iter;
 14.2624 +
 14.2625 +	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
 14.2626 +	{
 14.2627 +		(*iter)->SyncMaxClients(max_clients);
 14.2628 +	}
 14.2629 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/core/PluginSys.h	Mon Nov 24 08:39:46 2008 -0600
    15.3 @@ -0,0 +1,458 @@
    15.4 +/**
    15.5 + * vim: set ts=4 :
    15.6 + * =============================================================================
    15.7 + * SourceMod
    15.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    15.9 + * =============================================================================
   15.10 + *
   15.11 + * This program is free software; you can redistribute it and/or modify it under
   15.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   15.13 + * Free Software Foundation.
   15.14 + * 
   15.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   15.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   15.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   15.18 + * details.
   15.19 + *
   15.20 + * You should have received a copy of the GNU General Public License along with
   15.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   15.22 + *
   15.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   15.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   15.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   15.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   15.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   15.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   15.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   15.30 + * or <http://www.sourcemod.net/license.php>.
   15.31 + *
   15.32 + * Version: $Id$
   15.33 + */
   15.34 +
   15.35 +#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
   15.36 +#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
   15.37 +
   15.38 +#include <time.h>
   15.39 +#include <errno.h>
   15.40 +#include <sys/stat.h>
   15.41 +#include <IPluginSys.h>
   15.42 +#include <IHandleSys.h>
   15.43 +#include <IForwardSys.h>
   15.44 +#include <sh_list.h>
   15.45 +#include <sh_stack.h>
   15.46 +#include <sh_vector.h>
   15.47 +#include <sh_string.h>
   15.48 +#include "sm_globals.h"
   15.49 +#include "PluginInfoDatabase.h"
   15.50 +#include "sm_trie.h"
   15.51 +#include "sourcemod.h"
   15.52 +#include <IRootConsoleMenu.h>
   15.53 +#if defined ORANGEBOX_BUILD
   15.54 +#include "convar_sm_ob.h"
   15.55 +#else
   15.56 +#include "convar_sm.h"
   15.57 +#endif
   15.58 +#include "ITranslator.h"
   15.59 +#include "NativeOwner.h"
   15.60 +#include "ShareSys.h"
   15.61 +
   15.62 +using namespace SourceHook;
   15.63 +
   15.64 +/**
   15.65 + * NOTES:
   15.66 + *
   15.67 + * UPDATE 2008-03-11: These comments are horribly out of date.  They paint a good overall 
   15.68 + * picture of how PluginSys works, but things like dependencies and fake natives have 
   15.69 + * complicated things quite a bit.
   15.70 + *
   15.71 + *  Currently this system needs a lot of work but it's good skeletally.  Plugin creation 
   15.72 + * is done without actually compiling anything.  This is done by Load functions in the 
   15.73 + * manager.  This will need a rewrite when we add context switching.
   15.74 + *
   15.75 + *  The plugin object itself has a few things to note.  The most important is that it stores
   15.76 + * a table of function objects.  The manager marshals allocation and freeing of these objects.
   15.77 + * The plugin object can be in erroneous states, they are:
   15.78 + *   Plugin_Error   --> Some error occurred any time during or after compilation.
   15.79 + *						This error can be cleared since the plugin itself is valid.
   15.80 + *						However, the state itself being set prevents any runtime action.
   15.81 + *   Plugin_BadLoad	--> The plugin failed to load entirely and nothing can be done to save it.
   15.82 + *
   15.83 + *  If a plugin fails to load externally, it is never added to the internal tracker.  However, 
   15.84 + * plugins that failed to load from the internal loading mechanism are always tracked.  This 
   15.85 + * allows users to see which automatically loaded plugins failed, and makes the interface a bit
   15.86 + * more flexible.
   15.87 + *
   15.88 + *  Once a plugin is compiled, it sets its own state to Plugin_Created.  This state is still invalid
   15.89 + * for execution.  SourceMod is a two pass system, and even though the second pass is not implemented
   15.90 + * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass.  When
   15.91 + * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
   15.92 + *
   15.93 + *  The two pass loading mechanism is described below.  Modules/natives are not implemented yet.
   15.94 + * PASS ONE: All loadable plugins are found and have the following steps performed:
   15.95 + *			 1.  Loading and compilation is attempted.
   15.96 + *			 2.  If successful, all natives from Core are added.
   15.97 + *			 3.  OnPluginLoad() is called.
   15.98 + *			 4.  If failed, any user natives are scrapped and the process halts here.
   15.99 + *			 5.  If successful, the plugin is ready for Pass 2.
  15.100 + * INTERMEDIATE:
  15.101 + *			 1.  All forced modules are loaded.
  15.102 + * PASS TWO: All loaded plugins are found and have these steps performed:
  15.103 + *			 1. Any modules referenced in the plugin that are not already loaded, are loaded.
  15.104 + *			 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
  15.105 + *			 3. If any natives are unresolved, check if they are found in the user-natives pool.
  15.106 + *			 4. If yes, load succeeds.  If not, natives are passed through a native acceptance filter.
  15.107 + *			 5. If the filter fails, the plugin is marked as failed.
  15.108 + *			 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
  15.109 + *			    Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
  15.110 + * PASS THREE (not a real pass):
  15.111 + *			 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
  15.112 + */
  15.113 +
  15.114 +enum LoadRes
  15.115 +{
  15.116 +	LoadRes_Successful,
  15.117 +	LoadRes_AlreadyLoaded,
  15.118 +	LoadRes_Failure,
  15.119 +	LoadRes_NeverLoad
  15.120 +};
  15.121 +
  15.122 +struct AutoConfig
  15.123 +{
  15.124 +	String autocfg;
  15.125 +	String folder;
  15.126 +	bool create;
  15.127 +};
  15.128 +
  15.129 +class CPlugin;
  15.130 +
  15.131 +class CPlugin : 
  15.132 +	public IPlugin,
  15.133 +	public CNativeOwner
  15.134 +{
  15.135 +	friend class CPluginManager;
  15.136 +	friend class CFunction;
  15.137 +public:
  15.138 +	CPlugin(const char *file);
  15.139 +	~CPlugin();
  15.140 +public:
  15.141 +	PluginType GetType();
  15.142 +	SourcePawn::IPluginContext *GetBaseContext();
  15.143 +	sp_context_t *GetContext();
  15.144 +	void *GetPluginStructure();
  15.145 +	const char *GetFilename();
  15.146 +	bool IsDebugging();
  15.147 +	PluginStatus GetStatus();
  15.148 +	const sm_plugininfo_t *GetPublicInfo();
  15.149 +	bool SetPauseState(bool paused);
  15.150 +	unsigned int GetSerial();
  15.151 +	IdentityToken_t *GetIdentity();
  15.152 +	unsigned int CalcMemUsage();
  15.153 +	bool SetProperty(const char *prop, void *ptr);
  15.154 +	bool GetProperty(const char *prop, void **ptr, bool remove=false);
  15.155 +	void DropEverything();
  15.156 +	SourcePawn::IPluginRuntime *GetRuntime();
  15.157 +public:
  15.158 +	/**
  15.159 +	 * Creates a plugin object with default values.
  15.160 +	 *   If an error buffer is specified, and an error occurs, the error will be copied to the buffer
  15.161 +	 * and NULL will be returned.
  15.162 +	 *   If an error buffer is not specified, the error will be copied to an internal buffer and 
  15.163 +	 * a valid (but error-stated) CPlugin will be returned.
  15.164 +	 */
  15.165 +	static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
  15.166 +public:
  15.167 +
  15.168 +	/**
  15.169 +	 * Sets an error state on the plugin
  15.170 +	 */
  15.171 +	void SetErrorState(PluginStatus status, const char *error_fmt, ...);
  15.172 +
  15.173 +	/**
  15.174 +	 * Initializes the plugin's identity information
  15.175 +	 */
  15.176 +	void InitIdentity();
  15.177 +
  15.178 +	/**
  15.179 +	 * Calls the OnPluginLoad function, and sets any failed states if necessary.
  15.180 +	 * NOTE: Valid pre-states are: Plugin_Created
  15.181 +	 * NOTE: If validated, plugin state is changed to Plugin_Loaded
  15.182 +	 *
  15.183 +	 * If the error buffer is NULL, the error message is cached locally.
  15.184 +	 */
  15.185 +	bool Call_AskPluginLoad(char *error, size_t maxlength);
  15.186 +
  15.187 +	/**
  15.188 +	 * Calls the OnPluginStart function.
  15.189 +	 * NOTE: Valid pre-states are: Plugin_Created
  15.190 +	 * NOTE: Post-state will be Plugin_Running
  15.191 +	 */
  15.192 +	void Call_OnPluginStart();
  15.193 +
  15.194 +	/**
  15.195 +	 * Calls the OnPluginEnd function.
  15.196 +	 */
  15.197 +	void Call_OnPluginEnd();
  15.198 +
  15.199 +	/**
  15.200 +	 * Calls the OnAllPluginsLoaded function.
  15.201 +	 */
  15.202 +	void Call_OnAllPluginsLoaded();
  15.203 +
  15.204 +	/**
  15.205 +	 * Returns true if a plugin is usable.
  15.206 +	 */
  15.207 +	bool IsRunnable();
  15.208 +
  15.209 +	/**
  15.210 +	 * Get languages info.
  15.211 +	 */
  15.212 +	IPhraseCollection *GetPhrases();
  15.213 +public:
  15.214 +	/**
  15.215 +	 * Returns the modification time during last plugin load.
  15.216 +	 */
  15.217 +	time_t GetTimeStamp();
  15.218 +
  15.219 +	/**
  15.220 +	 * Returns the current modification time of the plugin file.
  15.221 +	 */
  15.222 +	time_t GetFileTimeStamp();
  15.223 +
  15.224 +	/** 
  15.225 +	 * Returns true if the plugin was running, but is now invalid.
  15.226 +	 */
  15.227 +	bool WasRunning();
  15.228 +
  15.229 +	Handle_t GetMyHandle();
  15.230 +
  15.231 +	bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
  15.232 +	void AddConfig(bool autoCreate, const char *cfg, const char *folder);
  15.233 +	unsigned int GetConfigCount();
  15.234 +	AutoConfig *GetConfig(unsigned int i);
  15.235 +	inline void AddLibrary(const char *name)
  15.236 +	{
  15.237 +		m_Libraries.push_back(name);
  15.238 +	}
  15.239 +	void LibraryActions(bool dropping);
  15.240 +	void SyncMaxClients(int max_clients);
  15.241 +protected:
  15.242 +	bool UpdateInfo();
  15.243 +	void SetTimeStamp(time_t t);
  15.244 +	void DependencyDropped(CPlugin *pOwner);
  15.245 +private:
  15.246 +	PluginType m_type;
  15.247 +	char m_filename[PLATFORM_MAX_PATH];
  15.248 +	PluginStatus m_status;
  15.249 +	unsigned int m_serial;
  15.250 +	sm_plugininfo_t m_info;
  15.251 +	char m_errormsg[256];
  15.252 +	time_t m_LastAccess;
  15.253 +	IdentityToken_t *m_ident;
  15.254 +	Handle_t m_handle;
  15.255 +	bool m_WasRunning;
  15.256 +	IPhraseCollection *m_pPhrases;
  15.257 +	List<String> m_RequiredLibs;
  15.258 +	List<String> m_Libraries;
  15.259 +	Trie *m_pProps;
  15.260 +	bool m_FakeNativesMissing;
  15.261 +	bool m_LibraryMissing;
  15.262 +	CVector<AutoConfig *> m_configs;
  15.263 +	bool m_bGotAllLoaded;
  15.264 +	int m_FileVersion;
  15.265 +	char m_DateTime[256];
  15.266 +	IPluginRuntime *m_pRuntime;
  15.267 +	IPluginContext *m_pContext;
  15.268 +	sp_pubvar_t *m_MaxClientsVar;
  15.269 +};
  15.270 +
  15.271 +class CPluginManager : 
  15.272 +	public IPluginManager,
  15.273 +	public SMGlobalClass,
  15.274 +	public IHandleTypeDispatch,
  15.275 +	public IRootConsoleCommand
  15.276 +{
  15.277 +	friend class CPlugin;
  15.278 +public:
  15.279 +	CPluginManager();
  15.280 +	~CPluginManager();
  15.281 +public:
  15.282 +	/* Implements iterator class */
  15.283 +	class CPluginIterator : public IPluginIterator
  15.284 +	{
  15.285 +	public:
  15.286 +		CPluginIterator(List<CPlugin *> *mylist);
  15.287 +		virtual ~CPluginIterator();
  15.288 +		virtual bool MorePlugins();
  15.289 +		virtual IPlugin *GetPlugin();
  15.290 +		virtual void NextPlugin();
  15.291 +		void Release();
  15.292 +	public:
  15.293 +		void Reset();
  15.294 +	private:
  15.295 +		List<CPlugin *> *mylist;
  15.296 +		List<CPlugin *>::iterator current;
  15.297 +	};
  15.298 +	friend class CPluginManager::CPluginIterator;
  15.299 +public: //IPluginManager
  15.300 +	IPlugin *LoadPlugin(const char *path, 
  15.301 +								bool debug,
  15.302 +								PluginType type,
  15.303 +								char error[],
  15.304 +								size_t maxlength,
  15.305 +								bool *wasloaded);
  15.306 +	bool UnloadPlugin(IPlugin *plugin);
  15.307 +	IPlugin *FindPluginByContext(const sp_context_t *ctx);
  15.308 +	unsigned int GetPluginCount();
  15.309 +	IPluginIterator *GetPluginIterator();
  15.310 +	void AddPluginsListener(IPluginsListener *listener);
  15.311 +	void RemovePluginsListener(IPluginsListener *listener);
  15.312 +public: //SMGlobalClass
  15.313 +	void OnSourceModAllInitialized();
  15.314 +	void OnSourceModShutdown();
  15.315 +	void OnSourceModMaxPlayersChanged(int newvalue);
  15.316 +public: //IHandleTypeDispatch
  15.317 +	void OnHandleDestroy(HandleType_t type, void *object);
  15.318 +	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
  15.319 +public: //IRootConsoleCommand
  15.320 +	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
  15.321 +public:
  15.322 +	/**
  15.323 +	 * Loads all plugins not yet loaded
  15.324 +	 */
  15.325 +	void LoadAll_FirstPass(const char *config, const char *basedir);
  15.326 +
  15.327 +	/**
  15.328 +	 * Runs the second loading pass for all plugins
  15.329 +	 */
  15.330 +	void LoadAll_SecondPass();
  15.331 +
  15.332 +	/**
  15.333 +	 * Tests a plugin file mask against a local folder.
  15.334 +	 * The alias is searched backwards from localdir - i.e., given this input:
  15.335 +	 *   csdm/ban        csdm/ban
  15.336 +	 *   ban             csdm/ban
  15.337 +	 *   csdm/ban        optional/csdm/ban
  15.338 +	 * All of these will return true for an alias match.  
  15.339 +	 * Wildcards are allowed in the filename.
  15.340 +	 */
  15.341 +	bool TestAliasMatch(const char *alias, const char *localdir);
  15.342 +
  15.343 +	/** 
  15.344 +	 * Returns whether anything loaded will be a late load.
  15.345 +	 */
  15.346 +	bool IsLateLoadTime() const;
  15.347 +
  15.348 +	/**
  15.349 +	 * Converts a Handle to an IPlugin if possible.
  15.350 +	 */
  15.351 +	IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
  15.352 +
  15.353 +	/**
  15.354 +	 * Finds a plugin based on its index. (starts on index 1)
  15.355 +	 */
  15.356 +	CPlugin *GetPluginByOrder(int num);
  15.357 +
  15.358 +	int GetOrderOfPlugin(IPlugin *pl);
  15.359 +
  15.360 +	/** 
  15.361 +	 * Internal version of FindPluginByContext()
  15.362 +	 */
  15.363 +	CPlugin *GetPluginByCtx(const sp_context_t *ctx);
  15.364 +
  15.365 +	/**
  15.366 +	 * Gets status text for a status code 
  15.367 +	 */
  15.368 +	const char *GetStatusText(PluginStatus status);
  15.369 +
  15.370 +	/**
  15.371 +	* Reload or update plugins on level shutdown.
  15.372 +	*/
  15.373 +	void ReloadOrUnloadPlugins();
  15.374 +
  15.375 +	/**
  15.376 +	 * Add public functions from all running or paused
  15.377 +	 * plugins to the specified forward if the names match.
  15.378 +	 */
  15.379 +	void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
  15.380 +
  15.381 +	/**
  15.382 +	 * Iterates through plugins to call OnAllPluginsLoaded.
  15.383 +	 */
  15.384 +	void AllPluginsLoaded();
  15.385 +
  15.386 +	CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
  15.387 +
  15.388 +	void Shutdown();
  15.389 +
  15.390 +	void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
  15.391 +
  15.392 +	bool LibraryExists(const char *lib);
  15.393 +
  15.394 +	bool ReloadPlugin(CPlugin *pl);
  15.395 +
  15.396 +	void UnloadAll();
  15.397 +
  15.398 +	CPlugin *FindPluginByConsoleArg(const char *arg);
  15.399 +
  15.400 +	void SyncMaxClients(int max_clients);
  15.401 +private:
  15.402 +	LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
  15.403 +
  15.404 +	void LoadAutoPlugin(const char *plugin);
  15.405 +
  15.406 +	/**
  15.407 +	 * Recursively loads all plugins in the given directory.
  15.408 +	 */
  15.409 +	void LoadPluginsFromDir(const char *basedir, const char *localdir);
  15.410 +
  15.411 +	/**
  15.412 +	 * Adds a plugin object.  This is wrapped by LoadPlugin functions.
  15.413 +	 */
  15.414 +	void AddPlugin(CPlugin *pPlugin);
  15.415 +
  15.416 +	/**
  15.417 +	 * Runs the second loading pass on a plugin.
  15.418 +	 */
  15.419 +	bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
  15.420 +
  15.421 +	/**
  15.422 +	 * Runs an extension pass on a plugin.
  15.423 +	 */
  15.424 +	bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
  15.425 +
  15.426 +	/**
  15.427 +	* Manages required natives.
  15.428 +	*/
  15.429 +	bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
  15.430 +
  15.431 +	void _SetPauseState(CPlugin *pPlugin, bool pause);
  15.432 +protected:
  15.433 +	/**
  15.434 +	 * Caching internal objects
  15.435 +	 */
  15.436 +	void ReleaseIterator(CPluginIterator *iter);
  15.437 +public:
  15.438 +	inline IdentityToken_t *GetIdentity()
  15.439 +	{
  15.440 +		return m_MyIdent;
  15.441 +	}
  15.442 +private:
  15.443 +	void TryRefreshDependencies(CPlugin *pOther);
  15.444 +private:
  15.445 +	List<IPluginsListener *> m_listeners;
  15.446 +	List<CPlugin *> m_plugins;
  15.447 +	CStack<CPluginManager::CPluginIterator *> m_iters;
  15.448 +	CPluginInfoDatabase m_PluginInfo;
  15.449 +	Trie *m_LoadLookup;
  15.450 +	bool m_AllPluginsLoaded;
  15.451 +	IdentityToken_t *m_MyIdent;
  15.452 +
  15.453 +	/* Dynamic native stuff */
  15.454 +	List<FakeNative *> m_Natives;
  15.455 +
  15.456 +	bool m_LoadingLocked;
  15.457 +};
  15.458 +
  15.459 +extern CPluginManager g_PluginSys;
  15.460 +
  15.461 +#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/core/ShareSys.cpp	Mon Nov 24 08:39:46 2008 -0600
    16.3 @@ -0,0 +1,529 @@
    16.4 +/**
    16.5 + * vim: set ts=4 :
    16.6 + * =============================================================================
    16.7 + * SourceMod
    16.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    16.9 + * =============================================================================
   16.10 + *
   16.11 + * This program is free software; you can redistribute it and/or modify it under
   16.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   16.13 + * Free Software Foundation.
   16.14 + * 
   16.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   16.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   16.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   16.18 + * details.
   16.19 + *
   16.20 + * You should have received a copy of the GNU General Public License along with
   16.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   16.22 + *
   16.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   16.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   16.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   16.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   16.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   16.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   16.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   16.30 + * or <http://www.sourcemod.net/license.php>.
   16.31 + *
   16.32 + * Version: $Id$
   16.33 + */
   16.34 +
   16.35 +#include "ShareSys.h"
   16.36 +#include "HandleSys.h"
   16.37 +#include "ExtensionSys.h"
   16.38 +#include "LibrarySys.h"
   16.39 +#include "PluginSys.h"
   16.40 +#include "sm_stringutil.h"
   16.41 +
   16.42 +ShareSystem g_ShareSys;
   16.43 +static unsigned int g_mark_serial = 0;
   16.44 +
   16.45 +ShareSystem::ShareSystem()
   16.46 +{
   16.47 +	m_IdentRoot.ident = 0;
   16.48 +	m_TypeRoot = 0;
   16.49 +	m_IfaceType = 0;
   16.50 +	m_CoreType = 0;
   16.51 +}
   16.52 +
   16.53 +IdentityToken_t *ShareSystem::CreateCoreIdentity()
   16.54 +{
   16.55 +	if (!m_CoreType)
   16.56 +	{
   16.57 +		m_CoreType = CreateIdentType("CORE");
   16.58 +	}
   16.59 +
   16.60 +	return CreateIdentity(m_CoreType, this);
   16.61 +}
   16.62 +
   16.63 +void ShareSystem::Initialize()
   16.64 +{
   16.65 +	TypeAccess sec;
   16.66 +
   16.67 +	g_HandleSys.InitAccessDefaults(&sec, NULL);
   16.68 +	sec.ident = GetIdentRoot();
   16.69 +
   16.70 +	m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
   16.71 +	m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
   16.72 +
   16.73 +	/* Initialize our static identity handle */
   16.74 +	m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
   16.75 +
   16.76 +	/* Add the Handle System and others... they are too innocent and pure to do it themselves */
   16.77 +	AddInterface(NULL, &g_HandleSys);
   16.78 +	AddInterface(NULL, &g_LibSys);
   16.79 +}
   16.80 +
   16.81 +void ShareSystem::OnSourceModShutdown()
   16.82 +{
   16.83 +	if (m_CoreType)
   16.84 +	{
   16.85 +		g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
   16.86 +	}
   16.87 +
   16.88 +	g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
   16.89 +	g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
   16.90 +}
   16.91 +
   16.92 +IdentityType_t ShareSystem::FindIdentType(const char *name)
   16.93 +{
   16.94 +	HandleType_t type;
   16.95 +
   16.96 +	if (g_HandleSys.FindHandleType(name, &type))
   16.97 +	{
   16.98 +		if (g_HandleSys.TypeCheck(type, m_TypeRoot))
   16.99 +		{
  16.100 +			return type;
  16.101 +		}
  16.102 +	}
  16.103 +
  16.104 +	return 0;
  16.105 +}
  16.106 +
  16.107 +IdentityType_t ShareSystem::CreateIdentType(const char *name)
  16.108 +{
  16.109 +	if (!m_TypeRoot)
  16.110 +	{
  16.111 +		return 0;
  16.112 +	}
  16.113 +
  16.114 +	return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
  16.115 +}
  16.116 +
  16.117 +void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
  16.118 +{
  16.119 +	/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
  16.120 +}
  16.121 +
  16.122 +IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
  16.123 +{
  16.124 +	if (!m_TypeRoot)
  16.125 +	{
  16.126 +		return 0;
  16.127 +	}
  16.128 +
  16.129 +	/* :TODO: Cache? */
  16.130 +	IdentityToken_t *pToken = new IdentityToken_t;
  16.131 +
  16.132 +	HandleSecurity sec;
  16.133 +	sec.pOwner = sec.pIdentity = GetIdentRoot();
  16.134 +
  16.135 +	pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
  16.136 +	pToken->ptr = ptr;
  16.137 +	pToken->type = type;
  16.138 +
  16.139 +	return pToken;
  16.140 +}
  16.141 +
  16.142 +bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
  16.143 +{
  16.144 +	if (!iface)
  16.145 +	{
  16.146 +		return false;
  16.147 +	}
  16.148 +
  16.149 +	IfaceInfo info;
  16.150 +
  16.151 +	info.owner = myself;
  16.152 +	info.iface = iface;
  16.153 +	
  16.154 +	m_Interfaces.push_back(info);
  16.155 +
  16.156 +	return true;
  16.157 +}
  16.158 +
  16.159 +bool ShareSystem::RequestInterface(const char *iface_name, 
  16.160 +								   unsigned int iface_vers, 
  16.161 +								   IExtension *myself, 
  16.162 +								   SMInterface **pIface)
  16.163 +{
  16.164 +	/* See if the interface exists */
  16.165 +	List<IfaceInfo>::iterator iter;
  16.166 +	SMInterface *iface;
  16.167 +	IExtension *iface_owner;
  16.168 +	bool found = false;
  16.169 +	for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
  16.170 +	{
  16.171 +		IfaceInfo &info = (*iter);
  16.172 +		iface = info.iface;
  16.173 +		if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
  16.174 +		{
  16.175 +			if (iface->GetInterfaceVersion() == iface_vers
  16.176 +				|| iface->IsVersionCompatible(iface_vers))
  16.177 +			{
  16.178 +				iface_owner = info.owner;
  16.179 +				found = true;
  16.180 +				break;
  16.181 +			}
  16.182 +		}
  16.183 +	}
  16.184 +
  16.185 +	if (!found)
  16.186 +	{
  16.187 +		return false;
  16.188 +	}
  16.189 +
  16.190 +	/* Add a dependency node */
  16.191 +	if (iface_owner)
  16.192 +	{
  16.193 +		IfaceInfo info;
  16.194 +		info.iface = iface;
  16.195 +		info.owner = iface_owner;
  16.196 +		g_Extensions.BindDependency(myself, &info);
  16.197 +	}
  16.198 +
  16.199 +	if (pIface)
  16.200 +	{
  16.201 +		*pIface = iface;
  16.202 +	}
  16.203 +
  16.204 +	return true;
  16.205 +}
  16.206 +
  16.207 +void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
  16.208 +{
  16.209 +	CNativeOwner *pOwner;
  16.210 +
  16.211 +	pOwner = g_Extensions.GetNativeOwner(myself);
  16.212 +
  16.213 +	pOwner->AddNatives(natives);
  16.214 +}
  16.215 +
  16.216 +void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
  16.217 +{
  16.218 +	HandleSecurity sec;
  16.219 +
  16.220 +	sec.pOwner = GetIdentRoot();
  16.221 +	sec.pIdentity = GetIdentRoot();
  16.222 +
  16.223 +	g_HandleSys.FreeHandle(identity->ident, &sec);
  16.224 +	delete identity;
  16.225 +}
  16.226 +
  16.227 +void ShareSystem::DestroyIdentType(IdentityType_t type)
  16.228 +{
  16.229 +	g_HandleSys.RemoveType(type, GetIdentRoot());
  16.230 +}
  16.231 +
  16.232 +void ShareSystem::RemoveInterfaces(IExtension *pExtension)
  16.233 +{
  16.234 +	List<IfaceInfo>::iterator iter = m_Interfaces.begin();
  16.235 +
  16.236 +	while (iter != m_Interfaces.end())
  16.237 +	{
  16.238 +		if ((*iter).owner == pExtension)
  16.239 +		{
  16.240 +			iter = m_Interfaces.erase(iter);
  16.241 +		}
  16.242 +		else
  16.243 +		{
  16.244 +			iter++;
  16.245 +		}
  16.246 +	}
  16.247 +}
  16.248 +
  16.249 +void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
  16.250 +{
  16.251 +	g_Extensions.AddDependency(myself, filename, require, autoload);
  16.252 +}
  16.253 +
  16.254 +void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
  16.255 +{
  16.256 +	g_Extensions.AddLibrary(myself, name);
  16.257 +}
  16.258 +
  16.259 +void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
  16.260 +{
  16.261 +	unsigned int i;
  16.262 +	NativeEntry *pEntry;
  16.263 +	CNativeOwner *pOwner;
  16.264 +
  16.265 +	pOwner = g_Extensions.GetNativeOwner(myself);
  16.266 +
  16.267 +	for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
  16.268 +	{
  16.269 +		if ((pEntry = FindNative(natives[i].name)) == NULL)
  16.270 +		{
  16.271 +			continue;
  16.272 +		}
  16.273 +
  16.274 +		if (pEntry->owner != g_pCoreNatives)
  16.275 +		{
  16.276 +			continue;
  16.277 +		}
  16.278 +
  16.279 +		if (pEntry->replacement.owner != NULL)
  16.280 +		{
  16.281 +			continue;
  16.282 +		}
  16.283 +
  16.284 +		/* Now it's safe to add the override */
  16.285 +		pEntry->replacement.func = natives[i].func;
  16.286 +		pEntry->replacement.owner = pOwner;
  16.287 +		pOwner->AddReplacedNative(pEntry);
  16.288 +	}
  16.289 +}
  16.290 +
  16.291 +NativeEntry *ShareSystem::FindNative(const char *name)
  16.292 +{
  16.293 +	NativeEntry **ppEntry;
  16.294 +
  16.295 +	if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
  16.296 +	{
  16.297 +		return NULL;
  16.298 +	}
  16.299 +
  16.300 +	return *ppEntry;
  16.301 +}
  16.302 +
  16.303 +void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
  16.304 +{
  16.305 +	NativeEntry *pEntry;
  16.306 +	sp_native_t *native;
  16.307 +	uint32_t i, native_count;
  16.308 +	IPluginContext *pContext;
  16.309 +
  16.310 +	pContext = pPlugin->GetBaseContext();
  16.311 +
  16.312 +	/* Generate a new serial ID, mark our dependencies with it. */
  16.313 +	g_mark_serial++;
  16.314 +	pPlugin->PropogateMarkSerial(g_mark_serial);
  16.315 +
  16.316 +	native_count = pContext->GetNativesNum();
  16.317 +	for (i = 0; i < native_count; i++)
  16.318 +	{
  16.319 +		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  16.320 +		{
  16.321 +			continue;
  16.322 +		}
  16.323 +
  16.324 +		/* If we're bound, check if there is a replacement available.  
  16.325 +		 * If not, this native is totally finalized.
  16.326 +		 */
  16.327 +		if (native->status == SP_NATIVE_BOUND)
  16.328 +		{
  16.329 +			pEntry = (NativeEntry *)native->user;
  16.330 +			assert(pEntry != NULL);
  16.331 +			if (pEntry->replacement.owner == NULL
  16.332 +				|| (pEntry->replacement.owner != NULL 
  16.333 +				&&  pEntry->replacement.func == native->pfn))
  16.334 +			{
  16.335 +				continue;
  16.336 +			}
  16.337 +		}
  16.338 +		/* Otherwise, the native must be in our cache. */
  16.339 +		else if ((pEntry = FindNative(native->name)) == NULL)
  16.340 +		{
  16.341 +			continue;
  16.342 +		}
  16.343 +
  16.344 +		if (bCoreOnly && pEntry->owner != g_pCoreNatives)
  16.345 +		{
  16.346 +			continue;
  16.347 +		}
  16.348 +
  16.349 +		BindNativeToPlugin(pPlugin, native, i, pEntry);
  16.350 +	}
  16.351 +}
  16.352 +
  16.353 +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
  16.354 +{
  16.355 +	uint32_t i;
  16.356 +	sp_native_t *native;
  16.357 +	IPluginContext *pContext;
  16.358 +
  16.359 +	pContext = pPlugin->GetBaseContext();
  16.360 +
  16.361 +	if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
  16.362 +	{
  16.363 +		return;
  16.364 +	}
  16.365 +	if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  16.366 +	{
  16.367 +		return;
  16.368 +	}
  16.369 +
  16.370 +	if (native->status == SP_NATIVE_BOUND)
  16.371 +	{
  16.372 +		return;
  16.373 +	}
  16.374 +
  16.375 +	BindNativeToPlugin(pPlugin, native, i, pEntry);
  16.376 +}
  16.377 +
  16.378 +void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, 
  16.379 +									 sp_native_t *native,
  16.380 +									 uint32_t index,
  16.381 +									 NativeEntry *pEntry)
  16.382 +{
  16.383 +	/* Mark as bound... we do the rest next. */
  16.384 +	native->status = SP_NATIVE_BOUND;
  16.385 +	native->user = pEntry;
  16.386 +
  16.387 +	/* See if a replacement is available. */
  16.388 +	if (pEntry->replacement.owner != NULL)
  16.389 +	{
  16.390 +		/* Perform a replacement bind. */
  16.391 +		native->pfn = pEntry->replacement.func;
  16.392 +		pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
  16.393 +	}
  16.394 +	else
  16.395 +	{
  16.396 +		/* Perform a normal bind. */
  16.397 +		native->pfn = pEntry->func;
  16.398 +
  16.399 +		/* We don't bother with dependency crap if the owner is Core. */
  16.400 +		if (pEntry->owner != g_pCoreNatives)
  16.401 +		{
  16.402 +			/* The native is optional, this is a special case */
  16.403 +			if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
  16.404 +			{
  16.405 +				/* Only add if there is a valid owner. */
  16.406 +				if (pEntry->owner != NULL)
  16.407 +				{
  16.408 +					pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
  16.409 +				}
  16.410 +				else
  16.411 +				{
  16.412 +					native->status = SP_NATIVE_UNBOUND;
  16.413 +				}
  16.414 +			}
  16.415 +			/* Otherwise, we're a strong dependent and not a weak one */
  16.416 +			else
  16.417 +			{
  16.418 +				/* See if this has already been marked as a dependent.
  16.419 +				 * If it has, it means this relationship has already occurred, 
  16.420 +				 * and there is no reason to do it again.
  16.421 +				 */
  16.422 +				if (pEntry->owner != pPlugin 
  16.423 +					&& pEntry->owner->GetMarkSerial() != g_mark_serial)
  16.424 +				{
  16.425 +					/* This has not been marked as a dependency yet */
  16.426 +					//pPlugin->AddDependency(pEntry->owner);
  16.427 +					pEntry->owner->AddDependent(pPlugin);
  16.428 +					pEntry->owner->SetMarkSerial(g_mark_serial);
  16.429 +				}
  16.430 +			}
  16.431 +		}
  16.432 +	}
  16.433 +}
  16.434 +
  16.435 +NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
  16.436 +{
  16.437 +	NativeEntry *pEntry;
  16.438 +
  16.439 +	if ((pEntry = FindNative(ntv->name)) == NULL)
  16.440 +	{
  16.441 +		pEntry = new NativeEntry;
  16.442 +
  16.443 +		pEntry->owner = pOwner;
  16.444 +		pEntry->name = ntv->name;
  16.445 +		pEntry->func = ntv->func;
  16.446 +		pEntry->replacement.func = NULL;
  16.447 +		pEntry->replacement.owner = NULL;
  16.448 +		pEntry->fake = NULL;
  16.449 +
  16.450 +		m_NtvCache.insert(ntv->name, pEntry);
  16.451 +
  16.452 +		return pEntry;
  16.453 +	}
  16.454 +
  16.455 +	if (pEntry->owner != NULL)
  16.456 +	{
  16.457 +		return NULL;
  16.458 +	}
  16.459 +
  16.460 +	pEntry->owner = pOwner;
  16.461 +	pEntry->func = ntv->func;
  16.462 +	pEntry->name = ntv->name;
  16.463 +
  16.464 +	return pEntry;
  16.465 +}
  16.466 +
  16.467 +void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
  16.468 +{
  16.469 +	NativeEntry *pEntry;
  16.470 +
  16.471 +	if ((pEntry = FindNative(name)) == NULL)
  16.472 +	{
  16.473 +		return;
  16.474 +	}
  16.475 +
  16.476 +	if (pEntry->owner != pOwner)
  16.477 +	{
  16.478 +		return;
  16.479 +	}
  16.480 +
  16.481 +	if (pEntry->fake != NULL)
  16.482 +	{
  16.483 +		g_pSourcePawn2->DestroyFakeNative(pEntry->func);
  16.484 +		delete pEntry->fake;
  16.485 +		pEntry->fake = NULL;
  16.486 +	}
  16.487 +
  16.488 +	pEntry->func = NULL;
  16.489 +	pEntry->name = NULL;
  16.490 +	pEntry->owner = NULL;
  16.491 +	pEntry->replacement.func = NULL;
  16.492 +	pEntry->replacement.owner = NULL;
  16.493 +}
  16.494 +
  16.495 +NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
  16.496 +{
  16.497 +	FakeNative *pFake;
  16.498 +	NativeEntry *pEntry;
  16.499 +	SPVM_NATIVE_FUNC gate;
  16.500 +
  16.501 +	if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
  16.502 +	{
  16.503 +		return NULL;
  16.504 +	}
  16.505 +
  16.506 +	pFake = new FakeNative;
  16.507 +
  16.508 +	if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
  16.509 +	{
  16.510 +		delete pFake;
  16.511 +		return NULL;
  16.512 +	}
  16.513 +
  16.514 +	if (pEntry == NULL)
  16.515 +	{
  16.516 +		pEntry = new NativeEntry;
  16.517 +		m_NtvCache.insert(name, pEntry);
  16.518 +	}
  16.519 +
  16.520 +	pFake->call = pFunc;
  16.521 +	pFake->ctx = pFunc->GetParentContext();
  16.522 +	strncopy(pFake->name, name, sizeof(pFake->name));
  16.523 +	
  16.524 +	pEntry->fake = pFake;
  16.525 +	pEntry->func = gate;
  16.526 +	pEntry->name = pFake->name;
  16.527 +	pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
  16.528 +	pEntry->replacement.func = NULL;
  16.529 +	pEntry->replacement.owner = NULL;
  16.530 +
  16.531 +	return pEntry;
  16.532 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/core/ShareSys.h	Mon Nov 24 08:39:46 2008 -0600
    17.3 @@ -0,0 +1,150 @@
    17.4 +/**
    17.5 + * vim: set ts=4 :
    17.6 + * =============================================================================
    17.7 + * SourceMod
    17.8 + * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    17.9 + * =============================================================================
   17.10 + *
   17.11 + * This program is free software; you can redistribute it and/or modify it under
   17.12 + * the terms of the GNU General Public License, version 3.0, as published by the
   17.13 + * Free Software Foundation.
   17.14 + * 
   17.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
   17.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   17.17 + * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   17.18 + * details.
   17.19 + *
   17.20 + * You should have received a copy of the GNU General Public License along with
   17.21 + * this program.  If not, see <http://www.gnu.org/licenses/>.
   17.22 + *
   17.23 + * As a special exception, AlliedModders LLC gives you permission to link the
   17.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
   17.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   17.26 + * by the Valve Corporation.  You must obey the GNU General Public License in
   17.27 + * all respects for all other code used.  Additionally, AlliedModders LLC grants
   17.28 + * this exception to all derivative works.  AlliedModders LLC defines further
   17.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   17.30 + * or <http://www.sourcemod.net/license.php>.
   17.31 + *
   17.32 + * Version: $Id$
   17.33 + */
   17.34 +
   17.35 +#ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
   17.36 +#define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
   17.37 +
   17.38 +#include <IShareSys.h>
   17.39 +#include <IHandleSys.h>
   17.40 +#include <sh_list.h>
   17.41 +#include <sm_trie_tpl.h>
   17.42 +#include "sm_globals.h"
   17.43 +#include "sourcemod.h"
   17.44 +
   17.45 +using namespace SourceHook;
   17.46 +
   17.47 +namespace SourceMod
   17.48 +{
   17.49 +	struct IdentityToken_t
   17.50 +	{
   17.51 +		Handle_t ident;
   17.52 +		void *ptr;
   17.53 +		IdentityType_t type;
   17.54 +	};
   17.55 +};
   17.56 +
   17.57 +struct IfaceInfo
   17.58 +{
   17.59 +	bool operator ==(const IfaceInfo &info)
   17.60 +	{
   17.61 +		return (info.iface == iface && info.owner == owner);
   17.62 +	}
   17.63 +	SMInterface *iface;
   17.64 +	IExtension *owner;
   17.65 +};
   17.66 +
   17.67 +class CNativeOwner;
   17.68 +class CPlugin;
   17.69 +struct NativeEntry;
   17.70 +
   17.71 +struct ReplaceNative
   17.72 +{
   17.73 +	CNativeOwner *owner;
   17.74 +	SPVM_NATIVE_FUNC func;
   17.75 +};
   17.76 +
   17.77 +struct FakeNative
   17.78 +{
   17.79 +	char name[64];
   17.80 +	IPluginContext *ctx;
   17.81 +	IPluginFunction *call;
   17.82 +};
   17.83 +
   17.84 +struct NativeEntry
   17.85 +{
   17.86 +	CNativeOwner *owner;
   17.87 +	SPVM_NATIVE_FUNC func;
   17.88 +	const char *name;
   17.89 +	ReplaceNative replacement;
   17.90 +	FakeNative *fake;
   17.91 +};
   17.92 +
   17.93 +class ShareSystem : 
   17.94 +	public IShareSys,
   17.95 +	public SMGlobalClass,
   17.96 +	public IHandleTypeDispatch
   17.97 +{
   17.98 +	friend class CNativeOwner;
   17.99 +public:
  17.100 +	ShareSystem();
  17.101 +public: //IShareSys
  17.102 +	bool AddInterface(IExtension *myself, SMInterface *pIface);
  17.103 +	bool RequestInterface(const char *iface_name, 
  17.104 +		unsigned int iface_vers,
  17.105 +		IExtension *myself,
  17.106 +		SMInterface **pIface);
  17.107 +	void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives);
  17.108 +	IdentityType_t CreateIdentType(const char *name);
  17.109 +	IdentityType_t FindIdentType(const char *name);
  17.110 +	IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr);
  17.111 +	void DestroyIdentType(IdentityType_t type);
  17.112 +	void DestroyIdentity(IdentityToken_t *identity);
  17.113 +	void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
  17.114 +	void RegisterLibrary(IExtension *myself, const char *name);
  17.115 +	void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
  17.116 +public: //SMGlobalClass
  17.117 +	/* Pre-empt in case anything tries to register idents early */
  17.118 +	void Initialize();
  17.119 +	void OnSourceModShutdown();
  17.120 +public: //IHandleTypeDispatch
  17.121 +	void OnHandleDestroy(HandleType_t type, void *object);
  17.122 +public:
  17.123 +	IdentityToken_t *CreateCoreIdentity();
  17.124 +	void RemoveInterfaces(IExtension *pExtension);
  17.125 +public:
  17.126 +	inline IdentityToken_t *GetIdentRoot()
  17.127 +	{
  17.128 +		return &m_IdentRoot;
  17.129 +	}
  17.130 +public:
  17.131 +	void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
  17.132 +	void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
  17.133 +	NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
  17.134 +private:
  17.135 +	NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
  17.136 +	void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
  17.137 +	NativeEntry *FindNative(const char *name);
  17.138 +	void BindNativeToPlugin(CPlugin *pPlugin, 
  17.139 +		sp_native_t *ntv, 
  17.140 +		uint32_t index, 
  17.141 +		NativeEntry *pEntry);
  17.142 +private:
  17.143 +	List<IfaceInfo> m_Interfaces;
  17.144 +	HandleType_t m_TypeRoot;
  17.145 +	IdentityToken_t m_IdentRoot;
  17.146 +	HandleType_t m_IfaceType;
  17.147 +	IdentityType_t m_CoreType;
  17.148 +	KTrie<NativeEntry *> m_NtvCache;
  17.149 +};
  17.150 +
  17.151 +extern ShareSystem g_ShareSys;
  17.152 +
  17.153 +#endif //_INCLUDE_SOURCEMOD_SHARESYSTEM_H_
    18.1 --- a/core/msvc8/sourcemod_mm.vcproj	Mon Nov 24 08:25:36 2008 -0600
    18.2 +++ b/core/msvc8/sourcemod_mm.vcproj	Mon Nov 24 08:39:46 2008 -0600
    18.3 @@ -1291,31 +1291,31 @@
    18.4  				UniqueIdentifier="{7D3AB33D-C1AD-46ee-B505-FEA8B6EF18E4}"
    18.5  				>
    18.6  				<File
    18.7 -					RelativePath="..\systems\ExtensionSys.h"
    18.8 +					RelativePath="..\ExtensionSys.h"
    18.9  					>
   18.10  				</File>
   18.11  				<File
   18.12 -					RelativePath="..\systems\ForwardSys.h"
   18.13 +					RelativePath="..\ForwardSys.h"
   18.14  					>
   18.15  				</File>
   18.16  				<File
   18.17 -					RelativePath="..\systems\HandleSys.h"
   18.18 +					RelativePath="..\HandleSys.h"
   18.19  					>
   18.20  				</File>
   18.21  				<File
   18.22 -					RelativePath="..\systems\LibrarySys.h"
   18.23 +					RelativePath="..\LibrarySys.h"
   18.24  					>
   18.25  				</File>
   18.26  				<File
   18.27 -					RelativePath="..\systems\PluginInfoDatabase.h"
   18.28 +					RelativePath="..\PluginInfoDatabase.h"
   18.29  					>
   18.30  				</File>
   18.31  				<File
   18.32 -					RelativePath="..\systems\PluginSys.h"
   18.33 +					RelativePath="..\PluginSys.h"
   18.34  					>
   18.35  				</File>
   18.36  				<File
   18.37 -					RelativePath="..\systems\ShareSys.h"
   18.38 +					RelativePath="..\ShareSys.h"
   18.39  					>
   18.40  				</File>
   18.41  			</Filter>
   18.42 @@ -1325,31 +1325,31 @@
   18.43  				UniqueIdentifier="{D1864A10-FF5F-4672-A70E-57C9F7486F92}"
   18.44  				>
   18.45  				<File
   18.46 -					RelativePath="..\systems\ExtensionSys.cpp"
   18.47 +					RelativePath="..\ExtensionSys.cpp"
   18.48  					>
   18.49  				</File>
   18.50  				<File
   18.51 -					RelativePath="..\systems\ForwardSys.cpp"
   18.52 +					RelativePath="..\ForwardSys.cpp"
   18.53  					>
   18.54  				</File>
   18.55  				<File
   18.56 -					RelativePath="..\systems\HandleSys.cpp"
   18.57 +					RelativePath="..\HandleSys.cpp"
   18.58  					>
   18.59  				</File>
   18.60  				<File
   18.61 -					RelativePath="..\systems\LibrarySys.cpp"
   18.62 +					RelativePath="..\LibrarySys.cpp"
   18.63  					>
   18.64  				</File>
   18.65  				<File
   18.66 -					RelativePath="..\systems\PluginInfoDatabase.cpp"
   18.67 +					RelativePath="..\PluginInfoDatabase.cpp"
   18.68  					>
   18.69  				</File>
   18.70  				<File
   18.71 -					RelativePath="..\systems\PluginSys.cpp"
   18.72 +					RelativePath="..\PluginSys.cpp"
   18.73  					>
   18.74  				</File>
   18.75  				<File
   18.76 -					RelativePath="..\systems\ShareSys.cpp"
   18.77 +					RelativePath="..\ShareSys.cpp"
   18.78  					>
   18.79  				</File>
   18.80  			</Filter>
    19.1 --- a/core/msvc9/sourcemod_mm.vcproj	Mon Nov 24 08:25:36 2008 -0600
    19.2 +++ b/core/msvc9/sourcemod_mm.vcproj	Mon Nov 24 08:39:46 2008 -0600
    19.3 @@ -854,6 +854,14 @@
    19.4  				>
    19.5  			</File>
    19.6  			<File
    19.7 +				RelativePath="..\ExtensionSys.cpp"
    19.8 +				>
    19.9 +			</File>
   19.10 +			<File
   19.11 +				RelativePath="..\ForwardSys.cpp"
   19.12 +				>
   19.13 +			</File>
   19.14 +			<File
   19.15  				RelativePath="..\frame_hooks.cpp"
   19.16  				>
   19.17  			</File>
   19.18 @@ -870,6 +878,14 @@
   19.19  				>
   19.20  			</File>
   19.21  			<File
   19.22 +				RelativePath="..\HandleSys.cpp"
   19.23 +				>
   19.24 +			</File>
   19.25 +			<File
   19.26 +				RelativePath="..\LibrarySys.cpp"
   19.27 +				>
   19.28 +			</File>
   19.29 +			<File
   19.30  				RelativePath="..\Logger.cpp"
   19.31  				>
   19.32  			</File>
   19.33 @@ -918,10 +934,22 @@
   19.34  				>
   19.35  			</File>
   19.36  			<File
   19.37 +				RelativePath="..\PluginInfoDatabase.cpp"
   19.38 +				>
   19.39 +			</File>
   19.40 +			<File
   19.41 +				RelativePath="..\PluginSys.cpp"
   19.42 +				>
   19.43 +			</File>
   19.44 +			<File
   19.45  				RelativePath="..\Profiler.cpp"
   19.46  				>
   19.47  			</File>
   19.48  			<File
   19.49 +				RelativePath="..\ShareSys.cpp"
   19.50 +				>
   19.51 +			</File>
   19.52 +			<File
   19.53  				RelativePath="..\sm_autonatives.cpp"
   19.54  				>
   19.55  			</File>
   19.56 @@ -1036,6 +1064,14 @@
   19.57  				>
   19.58  			</File>
   19.59  			<File
   19.60 +				RelativePath="..\ExtensionSys.h"
   19.61 +				>
   19.62 +			</File>
   19.63 +			<File
   19.64 +				RelativePath="..\ForwardSys.h"
   19.65 +				>
   19.66 +			</File>
   19.67 +			<File
   19.68  				RelativePath="..\frame_hooks.h"
   19.69  				>
   19.70  			</File>
   19.71 @@ -1052,6 +1088,14 @@
   19.72  				>
   19.73  			</File>
   19.74  			<File
   19.75 +				RelativePath="..\HandleSys.h"
   19.76 +				>
   19.77 +			</File>
   19.78 +			<File
   19.79 +				RelativePath="..\LibrarySys.h"
   19.80 +				>
   19.81 +			</File>
   19.82 +			<File
   19.83  				RelativePath="..\Logger.h"
   19.84  				>
   19.85  			</File>
   19.86 @@ -1100,10 +1144,22 @@
   19.87  				>
   19.88  			</File>
   19.89  			<File
   19.90 +				RelativePath="..\PluginInfoDatabase.h"
   19.91 +				>
   19.92 +			</File>
   19.93 +			<File
   19.94 +				RelativePath="..\PluginSys.h"
   19.95 +				>
   19.96 +			</File>
   19.97 +			<File
   19.98  				RelativePath="..\Profiler.h"
   19.99  				>
  19.100  			</File>
  19.101  			<File
  19.102 +				RelativePath="..\ShareSys.h"
  19.103 +				>
  19.104 +			</File>
  19.105 +			<File
  19.106  				RelativePath="..\sm_autonatives.h"
  19.107  				>
  19.108  			</File>
  19.109 @@ -1274,79 +1330,6 @@
  19.110  			</File>
  19.111  		</Filter>
  19.112  		<Filter
  19.113 -			Name="Systems"
  19.114 -			UniqueIdentifier="{63775418-DF3F-4198-BFB1-738B19EE3EE0}"
  19.115 -			>
  19.116 -			<Filter
  19.117 -				Name="Header Files"
  19.118 -				Filter="h;hpp;hxx;hm;inl;inc;xsd"
  19.119 -				UniqueIdentifier="{7D3AB33D-C1AD-46ee-B505-FEA8B6EF18E4}"
  19.120 -				>
  19.121 -				<File
  19.122 -					RelativePath="..\systems\ExtensionSys.h"
  19.123 -					>
  19.124 -				</File>
  19.125 -				<File
  19.126 -					RelativePath="..\systems\ForwardSys.h"
  19.127 -					>
  19.128 -				</File>
  19.129 -				<File
  19.130 -					RelativePath="..\systems\HandleSys.h"
  19.131 -					>
  19.132 -				</File>
  19.133 -				<File
  19.134 -					RelativePath="..\systems\LibrarySys.h"
  19.135 -					>
  19.136 -				</File>
  19.137 -				<File
  19.138 -					RelativePath="..\systems\PluginInfoDatabase.h"
  19.139 -					>
  19.140 -				</File>
  19.141 -				<File
  19.142 -					RelativePath="..\systems\PluginSys.h"
  19.143 -					>
  19.144 -				</File>
  19.145 -				<File
  19.146 -					RelativePath="..\systems\ShareSys.h"
  19.147 -					>
  19.148 -				</File>
  19.149 -			</Filter>
  19.150 -			<Filter
  19.151 -				Name="Source Files"
  19.152 -				Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
  19.153 -				UniqueIdentifier="{D1864A10-FF5F-4672-A70E-57C9F7486F92}"
  19.154 -				>
  19.155 -				<File
  19.156 -					RelativePath="..\systems\ExtensionSys.cpp"
  19.157 -					>
  19.158 -				</File>
  19.159 -				<File
  19.160 -					RelativePath="..\systems\ForwardSys.cpp"
  19.161 -					>
  19.162 -				</File>
  19.163 -				<File
  19.164 -					RelativePath="..\systems\HandleSys.cpp"
  19.165 -					>
  19.166 -				</File>
  19.167 -				<File
  19.168 -					RelativePath="..\systems\LibrarySys.cpp"
  19.169 -					>
  19.170 -				</File>
  19.171 -				<File
  19.172 -					RelativePath="..\systems\PluginInfoDatabase.cpp"
  19.173 -					>
  19.174 -				</File>
  19.175 -				<File
  19.176 -					RelativePath="..\systems\PluginSys.cpp"
  19.177 -					>
  19.178 -				</File>
  19.179 -				<File
  19.180 -					RelativePath="..\systems\ShareSys.cpp"
  19.181 -					>
  19.182 -				</File>
  19.183 -			</Filter>
  19.184 -		</Filter>
  19.185 -		<Filter
  19.186  			Name="SourcePawn"
  19.187  			UniqueIdentifier="{C3C3DC6E-E392-4916-B893-7ACB92192DE0}"
  19.188  			>
    20.1 --- a/core/sourcemod.cpp	Mon Nov 24 08:25:36 2008 -0600
    20.2 +++ b/core/sourcemod.cpp	Mon Nov 24 08:39:46 2008 -0600
    20.3 @@ -32,7 +32,7 @@
    20.4  #include <stdio.h>
    20.5  #include "sourcemod.h"
    20.6  #include "sourcemm_api.h"
    20.7 -#include "systems/LibrarySys.h"
    20.8 +#include "LibrarySys.h"
    20.9  #include <sh_string.h>
   20.10  #include "PluginSys.h"
   20.11  #include "ShareSys.h"
    21.1 --- a/core/systems/ExtensionSys.cpp	Mon Nov 24 08:25:36 2008 -0600
    21.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.3 @@ -1,1208 +0,0 @@
    21.4 -/**
    21.5 - * vim: set ts=4 :
    21.6 - * =============================================================================
    21.7 - * SourceMod
    21.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    21.9 - * =============================================================================
   21.10 - *
   21.11 - * This program is free software; you can redistribute it and/or modify it under
   21.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   21.13 - * Free Software Foundation.
   21.14 - * 
   21.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   21.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   21.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   21.18 - * details.
   21.19 - *
   21.20 - * You should have received a copy of the GNU General Public License along with
   21.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   21.22 - *
   21.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   21.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   21.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   21.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   21.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   21.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   21.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   21.30 - * or <http://www.sourcemod.net/license.php>.
   21.31 - *
   21.32 - * Version: $Id$
   21.33 - */
   21.34 -
   21.35 -#include <stdlib.h>
   21.36 -#include "ExtensionSys.h"
   21.37 -#include "LibrarySys.h"
   21.38 -#include "ShareSys.h"
   21.39 -#include "Logger.h"
   21.40 -#include "sourcemm_api.h"
   21.41 -#include "sm_srvcmds.h"
   21.42 -#include "sm_stringutil.h"
   21.43 -
   21.44 -CExtensionManager g_Extensions;
   21.45 -IdentityType_t g_ExtType;
   21.46 -
   21.47 -void CExtension::Initialize(const char *filename, const char *path)
   21.48 -{
   21.49 -	m_pAPI = NULL;
   21.50 -	m_pIdentToken = NULL;
   21.51 -	unload_code = 0;
   21.52 -	m_bFullyLoaded = false;
   21.53 -	m_File.assign(filename);
   21.54 -	m_Path.assign(path);
   21.55 -}
   21.56 -
   21.57 -CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
   21.58 -{
   21.59 -	Initialize(filename, path);
   21.60 -	m_pAPI = pAPI;
   21.61 -}
   21.62 -
   21.63 -CLocalExtension::CLocalExtension(const char *filename)
   21.64 -{
   21.65 -	m_PlId = 0;
   21.66 -	m_pLib = NULL;
   21.67 -
   21.68 -	char path[PLATFORM_MAX_PATH];
   21.69 -
   21.70 -	/* First see if there is an engine specific build! */
   21.71 -	g_SourceMod.BuildPath(Path_SM, 
   21.72 -		path, 
   21.73 -		PLATFORM_MAX_PATH, 
   21.74 -#if defined METAMOD_PLAPI_VERSION
   21.75 -#if defined ORANGEBOX_BUILD
   21.76 -		"extensions/auto.2.ep2/%s",
   21.77 -#else
   21.78 -		"extensions/auto.2.ep1/%s",
   21.79 -#endif //ORANGEBOX_BUILD
   21.80 -#else  //METAMOD_PLAPI_VERSION
   21.81 -		"extensions/auto.1.ep1/%s",
   21.82 -#endif //METAMOD_PLAPI_VERSION
   21.83 -		filename);
   21.84 -
   21.85 -	/* Try the "normal" version */
   21.86 -	if (!g_LibSys.IsPathFile(path))
   21.87 -	{
   21.88 -		g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
   21.89 -	}
   21.90 -
   21.91 -	Initialize(filename, path);
   21.92 -}
   21.93 -
   21.94 -bool CRemoteExtension::Load(char *error, size_t maxlength)
   21.95 -{
   21.96 -	if (!PerformAPICheck(error, maxlength))
   21.97 -	{
   21.98 -		m_pAPI = NULL;
   21.99 -		return false;
  21.100 -	}
  21.101 -
  21.102 -	if (!CExtension::Load(error, maxlength))
  21.103 -	{
  21.104 -		m_pAPI = NULL;
  21.105 -		return false;
  21.106 -	}
  21.107 -
  21.108 -	return true;
  21.109 -}
  21.110 -
  21.111 -bool CLocalExtension::Load(char *error, size_t maxlength)
  21.112 -{
  21.113 -	m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
  21.114 -
  21.115 -	if (m_pLib == NULL)
  21.116 -	{
  21.117 -		return false;
  21.118 -	}
  21.119 -
  21.120 -	typedef IExtensionInterface *(*GETAPI)();
  21.121 -	GETAPI pfnGetAPI = NULL;
  21.122 -
  21.123 -	if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
  21.124 -	{
  21.125 -		m_pLib->CloseLibrary();
  21.126 -		m_pLib = NULL;
  21.127 -		snprintf(error, maxlength, "Unable to find extension entry point");
  21.128 -		return false;
  21.129 -	}
  21.130 -
  21.131 -	m_pAPI = pfnGetAPI();
  21.132 -
  21.133 -	/* Check pointer and version */
  21.134 -	if (!PerformAPICheck(error, maxlength))
  21.135 -	{
  21.136 -		m_pLib->CloseLibrary();
  21.137 -		m_pLib = NULL;
  21.138 -		m_pAPI = NULL;
  21.139 -		return false;
  21.140 -	}
  21.141 -
  21.142 -	/* Load as MM:S */
  21.143 -	if (m_pAPI->IsMetamodExtension())
  21.144 -	{
  21.145 -		bool already;
  21.146 -		m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
  21.147 -	}
  21.148 -
  21.149 -	if (!CExtension::Load(error, maxlength))
  21.150 -	{
  21.151 -		if (m_pAPI->IsMetamodExtension())
  21.152 -		{
  21.153 -			if (m_PlId)
  21.154 -			{
  21.155 -				char dummy[255];
  21.156 -				g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
  21.157 -				m_PlId = 0;
  21.158 -			}
  21.159 -		}
  21.160 -		m_pLib->CloseLibrary();
  21.161 -		m_pLib = NULL;
  21.162 -		m_pAPI = NULL;
  21.163 -		return false;
  21.164 -	}
  21.165 -
  21.166 -	return true;
  21.167 -}
  21.168 -
  21.169 -void CRemoteExtension::Unload()
  21.170 -{
  21.171 -}
  21.172 -
  21.173 -void CLocalExtension::Unload()
  21.174 -{
  21.175 -	if (m_pAPI != NULL && m_PlId)
  21.176 -	{
  21.177 -		char temp_buffer[255];
  21.178 -		g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
  21.179 -		m_PlId = 0;
  21.180 -	}
  21.181 -
  21.182 -	if (m_pLib != NULL)
  21.183 -	{
  21.184 -		m_pLib->CloseLibrary();
  21.185 -		m_pLib = NULL;
  21.186 -	}
  21.187 -}
  21.188 -
  21.189 -bool CRemoteExtension::IsExternal()
  21.190 -{
  21.191 -	return true;
  21.192 -}
  21.193 -
  21.194 -bool CLocalExtension::IsExternal()
  21.195 -{
  21.196 -	return false;
  21.197 -}
  21.198 -
  21.199 -CExtension::~CExtension()
  21.200 -{
  21.201 -	DestroyIdentity();
  21.202 -}
  21.203 -
  21.204 -bool CExtension::PerformAPICheck(char *error, size_t maxlength)
  21.205 -{
  21.206 -	if (!m_pAPI)
  21.207 -	{
  21.208 -		snprintf(error, maxlength, "No IExtensionInterface instance provided");
  21.209 -		return false;
  21.210 -	}
  21.211 -	
  21.212 -	if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
  21.213 -	{
  21.214 -		snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
  21.215 -		return false;
  21.216 -	}
  21.217 -
  21.218 -	return true;
  21.219 -}
  21.220 -
  21.221 -bool CExtension::Load(char *error, size_t maxlength)
  21.222 -{
  21.223 -	CreateIdentity();
  21.224 -	if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
  21.225 -	{
  21.226 -		DestroyIdentity();
  21.227 -		return false;
  21.228 -	}
  21.229 -	else
  21.230 -	{
  21.231 -		/* Check if we're past load time */
  21.232 -		if (!g_SourceMod.IsMapLoading())
  21.233 -		{
  21.234 -			m_pAPI->OnExtensionsAllLoaded();
  21.235 -		}
  21.236 -	}
  21.237 -
  21.238 -	return true;
  21.239 -}
  21.240 -
  21.241 -void CExtension::CreateIdentity()
  21.242 -{
  21.243 -	if (m_pIdentToken != NULL)
  21.244 -	{
  21.245 -		return;
  21.246 -	}
  21.247 -
  21.248 -	m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
  21.249 -}
  21.250 -
  21.251 -void CExtension::DestroyIdentity()
  21.252 -{
  21.253 -	if (m_pIdentToken == NULL)
  21.254 -	{
  21.255 -		return;
  21.256 -	}
  21.257 -
  21.258 -	g_ShareSys.DestroyIdentity(m_pIdentToken);
  21.259 -	m_pIdentToken = NULL;
  21.260 -}
  21.261 -
  21.262 -void CExtension::MarkAllLoaded()
  21.263 -{
  21.264 -	assert(m_bFullyLoaded == false);
  21.265 -	if (!m_bFullyLoaded)
  21.266 -	{
  21.267 -		m_bFullyLoaded = true;
  21.268 -		m_pAPI->OnExtensionsAllLoaded();
  21.269 -	}
  21.270 -}
  21.271 -
  21.272 -void CExtension::AddPlugin(CPlugin *pPlugin)
  21.273 -{
  21.274 -	/* Unfortunately we have to do this :( */
  21.275 -	if (m_Dependents.find(pPlugin) != m_Dependents.end())
  21.276 -	{
  21.277 -		m_Dependents.push_back(pPlugin);
  21.278 -	}
  21.279 -}
  21.280 -
  21.281 -void CExtension::SetError(const char *error)
  21.282 -{
  21.283 -	m_Error.assign(error);
  21.284 -}
  21.285 -
  21.286 -IExtensionInterface *CExtension::GetAPI()
  21.287 -{
  21.288 -	return m_pAPI;
  21.289 -}
  21.290 -
  21.291 -const char *CExtension::GetFilename()
  21.292 -{
  21.293 -	return m_File.c_str();
  21.294 -}
  21.295 -
  21.296 -IdentityToken_t *CExtension::GetIdentity()
  21.297 -{
  21.298 -	return m_pIdentToken;
  21.299 -}
  21.300 -
  21.301 -bool CRemoteExtension::IsLoaded()
  21.302 -{
  21.303 -	return (m_pAPI != NULL);
  21.304 -}
  21.305 -
  21.306 -bool CLocalExtension::IsLoaded()
  21.307 -{
  21.308 -	return (m_pLib != NULL);
  21.309 -}
  21.310 -
  21.311 -void CExtension::AddDependency(const IfaceInfo *pInfo)
  21.312 -{
  21.313 -	if (m_Deps.find(*pInfo) == m_Deps.end())
  21.314 -	{
  21.315 -		m_Deps.push_back(*pInfo);
  21.316 -	}
  21.317 -}
  21.318 -
  21.319 -bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
  21.320 -{
  21.321 -	return (i1.iface == i2.iface) && (i1.owner == i2.owner);
  21.322 -}
  21.323 -
  21.324 -void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
  21.325 -{
  21.326 -	IfaceInfo info;
  21.327 -	info.iface = iface;
  21.328 -	info.owner = pOther;
  21.329 -
  21.330 -	List<IfaceInfo>::iterator iter;
  21.331 -	for (iter = m_ChildDeps.begin();
  21.332 -		 iter != m_ChildDeps.end();
  21.333 -		 iter++)
  21.334 -	{
  21.335 -		IfaceInfo &other = (*iter);
  21.336 -		if (other == info)
  21.337 -		{
  21.338 -			return;
  21.339 -		}
  21.340 -	}
  21.341 -
  21.342 -	m_ChildDeps.push_back(info);
  21.343 -}
  21.344 -
  21.345 -ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
  21.346 -{
  21.347 -	List<IfaceInfo>::iterator iter = m_Deps.begin();
  21.348 -
  21.349 -	if (iter == m_Deps.end())
  21.350 -	{
  21.351 -		return NULL;
  21.352 -	}
  21.353 -
  21.354 -	if (pOwner)
  21.355 -	{
  21.356 -		*pOwner = (*iter).owner;
  21.357 -	}
  21.358 -	if (pInterface)
  21.359 -	{
  21.360 -		*pInterface = (*iter).iface;
  21.361 -	}
  21.362 -
  21.363 -	List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
  21.364 -
  21.365 -	return (ITERATOR *)pIter;
  21.366 -}
  21.367 -
  21.368 -bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
  21.369 -{
  21.370 -	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
  21.371 -	List<IfaceInfo>::iterator _iter;
  21.372 -
  21.373 -	if (_iter == m_Deps.end())
  21.374 -	{
  21.375 -		return false;
  21.376 -	}
  21.377 -
  21.378 -	_iter++;
  21.379 -
  21.380 -	if (pOwner)
  21.381 -	{
  21.382 -		*pOwner = (*_iter).owner;
  21.383 -	}
  21.384 -	if (pInterface)
  21.385 -	{
  21.386 -		*pInterface = (*_iter).iface;
  21.387 -	}
  21.388 -
  21.389 -	*pIter = _iter;
  21.390 -
  21.391 -	if (_iter == m_Deps.end())
  21.392 -	{
  21.393 -		return false;
  21.394 -	}
  21.395 -
  21.396 -	return true;
  21.397 -}
  21.398 -
  21.399 -void CExtension::FreeDependencyIterator(ITERATOR *iter)
  21.400 -{
  21.401 -	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
  21.402 -
  21.403 -	delete pIter;
  21.404 -}
  21.405 -
  21.406 -void CExtension::AddInterface(SMInterface *pInterface)
  21.407 -{
  21.408 -	m_Interfaces.push_back(pInterface);
  21.409 -}
  21.410 -
  21.411 -bool CExtension::IsRunning(char *error, size_t maxlength)
  21.412 -{
  21.413 -	if (!IsLoaded())
  21.414 -	{
  21.415 -		if (error)
  21.416 -		{
  21.417 -			snprintf(error, maxlength, "%s", m_Error.c_str());
  21.418 -		}
  21.419 -		return false;
  21.420 -	}
  21.421 -
  21.422 -	return m_pAPI->QueryRunning(error, maxlength);
  21.423 -}
  21.424 -
  21.425 -void CExtension::AddLibrary(const char *library)
  21.426 -{
  21.427 -	m_Libraries.push_back(library);
  21.428 -}
  21.429 -
  21.430 -/*********************
  21.431 - * EXTENSION MANAGER *
  21.432 - *********************/
  21.433 -
  21.434 -void CExtensionManager::OnSourceModAllInitialized()
  21.435 -{
  21.436 -	g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
  21.437 -	g_PluginSys.AddPluginsListener(this);
  21.438 -	g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
  21.439 -	g_ShareSys.AddInterface(NULL, this);
  21.440 -}
  21.441 -
  21.442 -void CExtensionManager::OnSourceModShutdown()
  21.443 -{
  21.444 -	g_RootMenu.RemoveRootConsoleCommand("exts", this);
  21.445 -	g_ShareSys.DestroyIdentType(g_ExtType);
  21.446 -}
  21.447 -
  21.448 -void CExtensionManager::Shutdown()
  21.449 -{
  21.450 -	List<CExtension *>::iterator iter;
  21.451 -
  21.452 -	while ((iter = m_Libs.begin()) != m_Libs.end())
  21.453 -	{
  21.454 -		UnloadExtension((*iter));
  21.455 -	}
  21.456 -}
  21.457 -
  21.458 -void CExtensionManager::TryAutoload()
  21.459 -{
  21.460 -	char path[PLATFORM_MAX_PATH];
  21.461 -
  21.462 -	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
  21.463 -
  21.464 -	IDirectory *pDir = g_LibSys.OpenDirectory(path);
  21.465 -	if (!pDir)
  21.466 -	{
  21.467 -		return;
  21.468 -	}
  21.469 -
  21.470 -	const char *lfile;
  21.471 -	size_t len;
  21.472 -	while (pDir->MoreFiles())
  21.473 -	{
  21.474 -		if (pDir->IsEntryDirectory())
  21.475 -		{
  21.476 -			pDir->NextEntry();
  21.477 -			continue;
  21.478 -		}
  21.479 -
  21.480 -		lfile = pDir->GetEntryName();
  21.481 -		len = strlen(lfile);
  21.482 -		if (len <= 9) /* size of ".autoload" */
  21.483 -		{
  21.484 -			pDir->NextEntry();
  21.485 -			continue;
  21.486 -		}
  21.487 -
  21.488 -		if (strcmp(&lfile[len - 9], ".autoload") != 0)
  21.489 -		{
  21.490 -			pDir->NextEntry();
  21.491 -			continue;
  21.492 -		}
  21.493 -
  21.494 -		char file[PLATFORM_MAX_PATH];
  21.495 -		len = UTIL_Format(file, sizeof(file), "%s", lfile);
  21.496 -		strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
  21.497 -
  21.498 -		LoadAutoExtension(file);
  21.499 -		
  21.500 -		pDir->NextEntry();
  21.501 -	}
  21.502 -}
  21.503 -
  21.504 -IExtension *CExtensionManager::LoadAutoExtension(const char *path)
  21.505 -{
  21.506 -	if (!strstr(path, "." PLATFORM_LIB_EXT))
  21.507 -	{
  21.508 -		char newpath[PLATFORM_MAX_PATH];
  21.509 -		g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
  21.510 -		return LoadAutoExtension(newpath);
  21.511 -	}
  21.512 -
  21.513 -	IExtension *pAlready;
  21.514 -	if ((pAlready=FindExtensionByFile(path)) != NULL)
  21.515 -	{
  21.516 -		return pAlready;
  21.517 -	}
  21.518 -
  21.519 -	char error[256];
  21.520 -	CExtension *p = new CLocalExtension(path);
  21.521 -
  21.522 -	/* We put us in the list beforehand so extensions that check for each other
  21.523 -	 * won't recursively load each other.
  21.524 -	 */
  21.525 -	m_Libs.push_back(p);
  21.526 -
  21.527 -	if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
  21.528 -	{
  21.529 -		g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
  21.530 -		p->SetError(error);
  21.531 -	}
  21.532 -
  21.533 -	return p;
  21.534 -}
  21.535 -
  21.536 -IExtension *CExtensionManager::FindExtensionByFile(const char *file)
  21.537 -{
  21.538 -	List<CExtension *>::iterator iter;
  21.539 -	CExtension *pExt;
  21.540 -
  21.541 -	/* Chomp off the path */
  21.542 -	char lookup[PLATFORM_MAX_PATH];
  21.543 -	g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
  21.544 -
  21.545 -	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  21.546 -	{
  21.547 -		pExt = (*iter);
  21.548 -		char short_file[PLATFORM_MAX_PATH];
  21.549 -		g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
  21.550 -		if (strcmp(lookup, short_file) == 0)
  21.551 -		{
  21.552 -			return pExt;
  21.553 -		}
  21.554 -	}
  21.555 -
  21.556 -	/* If we got no results, test if there was a platform extension.
  21.557 -	 * If not, add one.
  21.558 -	 */
  21.559 -	if (!strstr(file, "." PLATFORM_LIB_EXT))
  21.560 -	{
  21.561 -		char path[PLATFORM_MAX_PATH];
  21.562 -		UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
  21.563 -		return FindExtensionByFile(path);
  21.564 -	}
  21.565 -
  21.566 -	return NULL;
  21.567 -}
  21.568 -
  21.569 -IExtension *CExtensionManager::FindExtensionByName(const char *ext)
  21.570 -{
  21.571 -	List<CExtension *>::iterator iter;
  21.572 -	CExtension *pExt;
  21.573 -	IExtensionInterface *pAPI;
  21.574 -	const char *name;
  21.575 -
  21.576 -	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  21.577 -	{
  21.578 -		pExt = (*iter);
  21.579 -		if (!pExt->IsLoaded())
  21.580 -		{
  21.581 -			continue;
  21.582 -		}
  21.583 -		if ((pAPI = pExt->GetAPI()) == NULL)
  21.584 -		{
  21.585 -			continue;
  21.586 -		}
  21.587 -		name = pAPI->GetExtensionName();
  21.588 -		if (!name)
  21.589 -		{
  21.590 -			continue;
  21.591 -		}
  21.592 -		if (strcmp(name, ext) == 0)
  21.593 -		{
  21.594 -			return pExt;
  21.595 -		}
  21.596 -	}
  21.597 -
  21.598 -	return NULL;
  21.599 -}
  21.600 -
  21.601 -IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
  21.602 -{
  21.603 -	IExtension *pAlready;
  21.604 -	if ((pAlready=FindExtensionByFile(file)) != NULL)
  21.605 -	{
  21.606 -		return pAlready;
  21.607 -	}
  21.608 -
  21.609 -	CExtension *pExt = new CLocalExtension(file);
  21.610 -
  21.611 -	if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
  21.612 -	{
  21.613 -		pExt->Unload();
  21.614 -		delete pExt;
  21.615 -		return NULL;
  21.616 -	}
  21.617 -
  21.618 -	/* :TODO: do QueryRunning check if the map is loaded */
  21.619 -
  21.620 -	m_Libs.push_back(pExt);
  21.621 -
  21.622 -	return pExt;
  21.623 -}
  21.624 -
  21.625 -void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
  21.626 -{
  21.627 -	CExtension *pExt = (CExtension *)pRequester;
  21.628 -	CExtension *pOwner = (CExtension *)pInfo->owner;
  21.629 -
  21.630 -	pExt->AddDependency(pInfo);
  21.631 -
  21.632 -	IExtensionInterface *pAPI = pExt->GetAPI();
  21.633 -	if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
  21.634 -	{
  21.635 -		pOwner->AddChildDependent(pExt, pInfo->iface);
  21.636 -	}
  21.637 -}
  21.638 -
  21.639 -void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface)
  21.640 -{
  21.641 -	CExtension *pExt = (CExtension *)ext;
  21.642 -	CExtension *pOwner = GetExtensionFromIdent(other);
  21.643 -
  21.644 -	IfaceInfo info;
  21.645 -
  21.646 -	info.iface = (SMInterface *)iface;
  21.647 -	info.owner = pOwner;
  21.648 -
  21.649 -	pExt->AddDependency(&info);
  21.650 -	pOwner->AddChildDependent(pExt, (SMInterface *)iface);
  21.651 -}
  21.652 -
  21.653 -void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
  21.654 -{
  21.655 -	CExtension *pExt = (CExtension *)pOwner;
  21.656 -
  21.657 -	pExt->AddInterface(pInterface);
  21.658 -}
  21.659 -
  21.660 -void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
  21.661 -{
  21.662 -	CExtension *pExt = (CExtension *)pParent;
  21.663 -
  21.664 -	pExt->AddPlugin(pPlugin);
  21.665 -}
  21.666 -
  21.667 -void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
  21.668 -{
  21.669 -	List<CExtension *>::iterator iter;
  21.670 -
  21.671 -	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  21.672 -	{
  21.673 -		(*iter)->DropRefsTo((CPlugin *)plugin);
  21.674 -	}
  21.675 -}
  21.676 -
  21.677 -CExtension *CExtensionManager::FindByOrder(unsigned int num)
  21.678 -{
  21.679 -	if (num < 1 || num > m_Libs.size())
  21.680 -	{
  21.681 -		return NULL;
  21.682 -	}
  21.683 -
  21.684 -	List<CExtension *>::iterator iter = m_Libs.begin();
  21.685 -
  21.686 -	while (iter != m_Libs.end())
  21.687 -	{
  21.688 -		if (--num == 0)
  21.689 -		{
  21.690 -			return (*iter);
  21.691 -		}
  21.692 -		iter++;
  21.693 -	}
  21.694 -
  21.695 -	return NULL;
  21.696 -}
  21.697 -
  21.698 -bool CExtensionManager::UnloadExtension(IExtension *_pExt)
  21.699 -{
  21.700 -	if (!_pExt)
  21.701 -	{
  21.702 -		return false;
  21.703 -	}
  21.704 -
  21.705 -	CExtension *pExt = (CExtension *)_pExt;
  21.706 -
  21.707 -	if (m_Libs.find(pExt) == m_Libs.end())
  21.708 -	{
  21.709 -		return false;
  21.710 -	}
  21.711 -
  21.712 -	/* First remove us from internal lists */
  21.713 -	g_ShareSys.RemoveInterfaces(_pExt);
  21.714 -	m_Libs.remove(pExt);
  21.715 -
  21.716 -	List<CExtension *> UnloadQueue;
  21.717 -
  21.718 -	/* Handle dependencies */
  21.719 -	if (pExt->IsLoaded())
  21.720 -	{
  21.721 -		/* Unload any dependent plugins */
  21.722 -		List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
  21.723 -		while (p_iter != pExt->m_Dependents.end())
  21.724 -		{
  21.725 -			/* We have to manually unlink ourselves here, since we're no longer being managed */
  21.726 -			g_PluginSys.UnloadPlugin((*p_iter));
  21.727 -			p_iter = pExt->m_Dependents.erase(p_iter);
  21.728 -		}
  21.729 -
  21.730 -		List<String>::iterator s_iter;
  21.731 -		for (s_iter = pExt->m_Libraries.begin();
  21.732 -			 s_iter != pExt->m_Libraries.end();
  21.733 -			 s_iter++)
  21.734 -		{
  21.735 -			g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
  21.736 -		}
  21.737 -
  21.738 -		/* Notify and/or unload all dependencies */
  21.739 -		List<CExtension *>::iterator c_iter;
  21.740 -		CExtension *pDep;
  21.741 -		IExtensionInterface *pAPI;
  21.742 -		for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
  21.743 -		{
  21.744 -			pDep = (*c_iter);
  21.745 -			if ((pAPI=pDep->GetAPI()) == NULL)
  21.746 -			{
  21.747 -				continue;
  21.748 -			}
  21.749 -			if (pDep == pExt)
  21.750 -			{
  21.751 -				continue;
  21.752 -			}
  21.753 -			/* Now, get its dependency list */
  21.754 -			bool dropped = false;
  21.755 -			List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
  21.756 -			while (i_iter != pDep->m_Deps.end())
  21.757 -			{
  21.758 -				if ((*i_iter).owner == _pExt)
  21.759 -				{
  21.760 -					if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
  21.761 -					{
  21.762 -						if (!dropped)
  21.763 -						{
  21.764 -							dropped = true;
  21.765 -							UnloadQueue.push_back(pDep);
  21.766 -						}
  21.767 -					}
  21.768 -					pAPI->NotifyInterfaceDrop((*i_iter).iface);
  21.769 -					i_iter = pDep->m_Deps.erase(i_iter);
  21.770 -				}
  21.771 -				else
  21.772 -				{
  21.773 -					i_iter++;
  21.774 -				}
  21.775 -			}
  21.776 -			/* Flush out any back references to this plugin */
  21.777 -			i_iter = pDep->m_ChildDeps.begin();
  21.778 -			while (i_iter != pDep->m_ChildDeps.end())
  21.779 -			{
  21.780 -				if ((*i_iter).owner == pExt)
  21.781 -				{
  21.782 -					i_iter = pDep->m_ChildDeps.erase(i_iter);
  21.783 -				}
  21.784 -				else
  21.785 -				{
  21.786 -					i_iter++;
  21.787 -				}
  21.788 -			}
  21.789 -		}
  21.790 -
  21.791 -		/* Unbind our natives from Core */
  21.792 -		pExt->DropEverything();
  21.793 -	}
  21.794 -
  21.795 -	IdentityToken_t *pIdentity;
  21.796 -	if ((pIdentity = pExt->GetIdentity()) != NULL)
  21.797 -	{
  21.798 -		SMGlobalClass *glob = SMGlobalClass::head;
  21.799 -		while (glob)
  21.800 -		{
  21.801 -			glob->OnSourceModIdentityDropped(pIdentity);
  21.802 -			glob = glob->m_pGlobalClassNext;
  21.803 -		}
  21.804 -	}
  21.805 -
  21.806 -	/* Tell it to unload */
  21.807 -	if (pExt->IsLoaded())
  21.808 -	{
  21.809 -		IExtensionInterface *pAPI = pExt->GetAPI();
  21.810 -		pAPI->OnExtensionUnload();
  21.811 -	}
  21.812 -
  21.813 -	pExt->Unload();
  21.814 -	delete pExt;
  21.815 -
  21.816 -	List<CExtension *>::iterator iter;
  21.817 -	for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
  21.818 -	{
  21.819 -		/* NOTE: This is safe because the unload function backs out of anything not present */
  21.820 -		UnloadExtension((*iter));
  21.821 -	}
  21.822 -
  21.823 -	return true;
  21.824 -}
  21.825 -
  21.826 -void CExtensionManager::MarkAllLoaded()
  21.827 -{
  21.828 -	List<CExtension *>::iterator iter;
  21.829 -	CExtension *pExt;
  21.830 -
  21.831 -	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
  21.832 -	{
  21.833 -		pExt = (*iter);
  21.834 -		if (!pExt->IsLoaded())
  21.835 -		{
  21.836 -			continue;
  21.837 -		}
  21.838 -		if (pExt->m_bFullyLoaded)
  21.839 -		{
  21.840 -			continue;
  21.841 -		}
  21.842 -		pExt->MarkAllLoaded();
  21.843 -	}
  21.844 -}
  21.845 -
  21.846 -void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
  21.847 -{
  21.848 -	/* This function doesn't really need to do anything now.  We make sure the 
  21.849 -	 * other extension is loaded, but handling of dependencies is really done 
  21.850 -	 * by the interface fetcher.
  21.851 -	 */
  21.852 -	if (required || autoload)
  21.853 -	{
  21.854 -		LoadAutoExtension(file);
  21.855 -	}
  21.856 -}
  21.857 -
  21.858 -void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
  21.859 -{
  21.860 -	int argcount = command.ArgC();
  21.861 -	if (argcount >= 3)
  21.862 -	{
  21.863 -		const char *cmd = command.Arg(2);
  21.864 -		if (strcmp(cmd, "list") == 0)
  21.865 -		{
  21.866 -			List<CExtension *>::iterator iter;
  21.867 -			CExtension *pExt;
  21.868 -			unsigned int num = 1;
  21.869 -			switch (m_Libs.size())
  21.870 -			{
  21.871 -			case 1:
  21.872 -				{
  21.873 -					g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
  21.874 -					break;
  21.875 -				}
  21.876 -			case 0:
  21.877 -				{
  21.878 -					g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
  21.879 -					break;
  21.880 -				}
  21.881 -			default:
  21.882 -				{
  21.883 -					g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
  21.884 -					break;
  21.885 -				}
  21.886 -			}
  21.887 -			for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
  21.888 -			{
  21.889 -				pExt = (*iter);
  21.890 -				if (pExt->IsLoaded())
  21.891 -				{
  21.892 -					char error[255];
  21.893 -					if (!pExt->IsRunning(error, sizeof(error)))
  21.894 -					{
  21.895 -						g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
  21.896 -					}
  21.897 -					else
  21.898 -					{
  21.899 -						IExtensionInterface *pAPI = pExt->GetAPI();
  21.900 -						const char *name = pAPI->GetExtensionName();
  21.901 -						const char *version = pAPI->GetExtensionVerString();
  21.902 -						const char *descr = pAPI->GetExtensionDescription();
  21.903 -						g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
  21.904 -					}
  21.905 -				} else {
  21.906 -					g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
  21.907 -				}
  21.908 -			}
  21.909 -			return;
  21.910 -		}
  21.911 -		else if (strcmp(cmd, "info") == 0)
  21.912 -		{
  21.913 -			if (argcount < 4)
  21.914 -			{
  21.915 -				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
  21.916 -				return;
  21.917 -			}
  21.918 -
  21.919 -			const char *sId = command.Arg(3);
  21.920 -			unsigned int id = atoi(sId);
  21.921 -			if (id <= 0)
  21.922 -			{
  21.923 -				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
  21.924 -				return;
  21.925 -			}
  21.926 -
  21.927 -			if (m_Libs.size() == 0)
  21.928 -			{
  21.929 -				g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
  21.930 -				return;
  21.931 -			}
  21.932 -
  21.933 -			if (id > m_Libs.size())
  21.934 -			{
  21.935 -				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
  21.936 -				return;
  21.937 -			}
  21.938 -
  21.939 -			List<CExtension *>::iterator iter = m_Libs.begin();
  21.940 -			CExtension *pExt = NULL;
  21.941 -			while (iter != m_Libs.end())
  21.942 -			{
  21.943 -				if (--id == 0)
  21.944 -				{
  21.945 -					pExt = (*iter);
  21.946 -					break;
  21.947 -				}
  21.948 -				iter++;
  21.949 -			}
  21.950 -			/* This should never happen */
  21.951 -			if (!pExt)
  21.952 -			{
  21.953 -				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
  21.954 -				return;
  21.955 -			}
  21.956 -
  21.957 -			if (!pExt->IsLoaded())
  21.958 -			{
  21.959 -				g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
  21.960 -				g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
  21.961 -			}
  21.962 -			else
  21.963 -			{
  21.964 -				char error[255];
  21.965 -				if (!pExt->IsRunning(error, sizeof(error)))
  21.966 -				{
  21.967 -					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
  21.968 -					g_RootMenu.ConsolePrint(" Loaded: Yes");
  21.969 -					g_RootMenu.ConsolePrint(" Running: No (%s)", error);
  21.970 -				}
  21.971 -				else
  21.972 -				{
  21.973 -					IExtensionInterface *pAPI = pExt->GetAPI();
  21.974 -					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
  21.975 -					g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
  21.976 -					g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
  21.977 -					g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
  21.978 -					g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
  21.979 -
  21.980 -					if (pExt->IsExternal())
  21.981 -					{
  21.982 -						g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
  21.983 -					}
  21.984 -					else if (pAPI->IsMetamodExtension())
  21.985 -					{
  21.986 -						g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
  21.987 -					}
  21.988 -					else
  21.989 -					{
  21.990 -						g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
  21.991 -					}
  21.992 -				}
  21.993 -			}
  21.994 -			return;
  21.995 -		}
  21.996 -		else if (strcmp(cmd, "unload") == 0)
  21.997 -		{
  21.998 -			if (argcount < 4)
  21.999 -			{
 21.1000 -				g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
 21.1001 -				return;
 21.1002 -			}
 21.1003 -
 21.1004 -			const char *arg = command.Arg(3);
 21.1005 -			unsigned int num = atoi(arg);
 21.1006 -			CExtension *pExt = FindByOrder(num);
 21.1007 -
 21.1008 -			if (!pExt)
 21.1009 -			{
 21.1010 -				g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
 21.1011 -				return;
 21.1012 -			}
 21.1013 -
 21.1014 -			if (argcount > 4 && pExt->unload_code)
 21.1015 -			{
 21.1016 -				const char *unload = command.Arg(4);
 21.1017 -				if (pExt->unload_code == (unsigned)atoi(unload))
 21.1018 -				{
 21.1019 -					char filename[PLATFORM_MAX_PATH];
 21.1020 -					snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
 21.1021 -					UnloadExtension(pExt);
 21.1022 -					g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
 21.1023 -				}
 21.1024 -				else
 21.1025 -				{
 21.1026 -					g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
 21.1027 -				}
 21.1028 -				return;
 21.1029 -			}
 21.1030 -
 21.1031 -			if (!pExt->IsLoaded() 
 21.1032 -				|| (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
 21.1033 -			{
 21.1034 -				char filename[PLATFORM_MAX_PATH];
 21.1035 -				snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
 21.1036 -				UnloadExtension(pExt);
 21.1037 -				g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
 21.1038 -				return;
 21.1039 -			}
 21.1040 -			else
 21.1041 -			{
 21.1042 -				List<CPlugin *> plugins;
 21.1043 -				if (pExt->m_ChildDeps.size())
 21.1044 -				{
 21.1045 -					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
 21.1046 -					List<CExtension *>::iterator iter;
 21.1047 -					CExtension *pOther;
 21.1048 -					/* Get list of all extensions */
 21.1049 -					for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
 21.1050 -					{
 21.1051 -						List<IfaceInfo>::iterator i_iter;
 21.1052 -						pOther = (*iter);
 21.1053 -						if (!pOther->IsLoaded() || pOther == pExt)
 21.1054 -						{
 21.1055 -							continue;
 21.1056 -						}
 21.1057 -						/* Get their dependencies */
 21.1058 -						for (i_iter=pOther->m_Deps.begin();
 21.1059 -							 i_iter!=pOther->m_Deps.end();
 21.1060 -							 i_iter++)
 21.1061 -						{
 21.1062 -							/* Is this dependency to us? */
 21.1063 -							if ((*i_iter).owner != pExt)
 21.1064 -							{
 21.1065 -								continue;
 21.1066 -							}
 21.1067 -							/* Will our dependent care? */
 21.1068 -							if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
 21.1069 -							{
 21.1070 -								g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
 21.1071 -								/* Add to plugin unload list */
 21.1072 -								List<CPlugin *>::iterator p_iter;
 21.1073 -								for (p_iter=pOther->m_Dependents.begin();
 21.1074 -									 p_iter!=pOther->m_Dependents.end();
 21.1075 -									 p_iter++)
 21.1076 -								{
 21.1077 -									if (plugins.find((*p_iter)) == plugins.end())
 21.1078 -									{
 21.1079 -										plugins.push_back((*p_iter));
 21.1080 -									}
 21.1081 -								}
 21.1082 -							}
 21.1083 -						}
 21.1084 -					}
 21.1085 -				}
 21.1086 -				if (pExt->m_Dependents.size())
 21.1087 -				{
 21.1088 -					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
 21.1089 -					List<CPlugin *>::iterator iter;
 21.1090 -					CPlugin *pPlugin;
 21.1091 -					for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
 21.1092 -					{
 21.1093 -						pPlugin = (*iter);
 21.1094 -						if (plugins.find(pPlugin) == plugins.end())
 21.1095 -						{
 21.1096 -							plugins.push_back(pPlugin);
 21.1097 -						}
 21.1098 -					}
 21.1099 -					for (iter = plugins.begin(); iter != plugins.end(); iter++)
 21.1100 -					{
 21.1101 -						pPlugin = (*iter);
 21.1102 -						g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
 21.1103 -					}
 21.1104 -				}
 21.1105 -				srand(static_cast<int>(time(NULL)));
 21.1106 -				pExt->unload_code = (rand() % 877) + 123;	//123 to 999
 21.1107 -				g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
 21.1108 -				g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
 21.1109 -
 21.1110 -				return;
 21.1111 -			}
 21.1112 -		}
 21.1113 -	}
 21.1114 -
 21.1115 -	g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
 21.1116 -	g_RootMenu.DrawGenericOption("info", "Extra extension information");
 21.1117 -	g_RootMenu.DrawGenericOption("list", "List extensions");
 21.1118 -	g_RootMenu.DrawGenericOption("unload", "Unload an extension");
 21.1119 -}
 21.1120 -
 21.1121 -CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
 21.1122 -{
 21.1123 -	if (ptr->type == g_ExtType)
 21.1124 -	{
 21.1125 -		return (CExtension *)(ptr->ptr);
 21.1126 -	}
 21.1127 -
 21.1128 -	return NULL;
 21.1129 -}
 21.1130 -
 21.1131 -CExtensionManager::CExtensionManager()
 21.1132 -{
 21.1133 -}
 21.1134 -
 21.1135 -CExtensionManager::~CExtensionManager()
 21.1136 -{
 21.1137 -}
 21.1138 -
 21.1139 -void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
 21.1140 -{
 21.1141 -	CExtension *pExt = (CExtension *)pSource;
 21.1142 -	pExt->AddLibrary(library);
 21.1143 -	g_PluginSys.OnLibraryAction(library, false, false);
 21.1144 -}
 21.1145 -
 21.1146 -bool CExtensionManager::LibraryExists(const char *library)
 21.1147 -{
 21.1148 -	CExtension *pExt;
 21.1149 -
 21.1150 -	for (List<CExtension *>::iterator iter = m_Libs.begin();
 21.1151 -		 iter != m_Libs.end();
 21.1152 -		 iter++)
 21.1153 -	{
 21.1154 -		pExt = (*iter);
 21.1155 -		for (List<String>::iterator s_iter = pExt->m_Libraries.begin();
 21.1156 -			 s_iter != pExt->m_Libraries.end();
 21.1157 -			 s_iter++)
 21.1158 -		{
 21.1159 -			if ((*s_iter).compare(library) == 0)
 21.1160 -			{
 21.1161 -				return true;
 21.1162 -			}
 21.1163 -		}
 21.1164 -	}
 21.1165 -
 21.1166 -	return false;
 21.1167 -}
 21.1168 -
 21.1169 -IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
 21.1170 -											const char *filepath,
 21.1171 -											const char *filename,
 21.1172 -											char *error,
 21.1173 -											size_t maxlength)
 21.1174 -{
 21.1175 -	IExtension *pAlready;
 21.1176 -	if ((pAlready=FindExtensionByFile(filename)) != NULL)
 21.1177 -	{
 21.1178 -		return pAlready;
 21.1179 -	}
 21.1180 -
 21.1181 -	CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
 21.1182 -
 21.1183 -	if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
 21.1184 -	{
 21.1185 -		pExt->Unload();
 21.1186 -		delete pExt;
 21.1187 -		return NULL;
 21.1188 -	}
 21.1189 -
 21.1190 -	m_Libs.push_back(pExt);
 21.1191 -
 21.1192 -	return pExt;
 21.1193 -}
 21.1194 -
 21.1195 -void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
 21.1196 -{
 21.1197 -	IExtensionInterface *pAPI;
 21.1198 -	List<CExtension *>::iterator iter;
 21.1199 -
 21.1200 -	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
 21.1201 -	{
 21.1202 -		if ((pAPI = (*iter)->GetAPI()) == NULL)
 21.1203 -		{
 21.1204 -			continue;
 21.1205 -		}
 21.1206 -		if (pAPI->GetExtensionVersion() > 3)
 21.1207 -		{
 21.1208 -			pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);
 21.1209 -		}
 21.1210 -	}
 21.1211 -}
    22.1 --- a/core/systems/ExtensionSys.h	Mon Nov 24 08:25:36 2008 -0600
    22.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.3 @@ -1,186 +0,0 @@
    22.4 -/**
    22.5 - * vim: set ts=4 :
    22.6 - * =============================================================================
    22.7 - * SourceMod
    22.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    22.9 - * =============================================================================
   22.10 - *
   22.11 - * This program is free software; you can redistribute it and/or modify it under
   22.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   22.13 - * Free Software Foundation.
   22.14 - * 
   22.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   22.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   22.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   22.18 - * details.
   22.19 - *
   22.20 - * You should have received a copy of the GNU General Public License along with
   22.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   22.22 - *
   22.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   22.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   22.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   22.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   22.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   22.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   22.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   22.30 - * or <http://www.sourcemod.net/license.php>.
   22.31 - *
   22.32 - * Version: $Id$
   22.33 - */
   22.34 -
   22.35 -#ifndef _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
   22.36 -#define _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
   22.37 -
   22.38 -#include <IExtensionSys.h>
   22.39 -#include <ILibrarySys.h>
   22.40 -#include <sh_list.h>
   22.41 -#include <sh_string.h>
   22.42 -#include <sm_trie_tpl.h>
   22.43 -#include "sm_globals.h"
   22.44 -#include "ShareSys.h"
   22.45 -#include <ISmmAPI.h>
   22.46 -#include <IPluginSys.h>
   22.47 -#include <IRootConsoleMenu.h>
   22.48 -#include "PluginSys.h"
   22.49 -#include "NativeOwner.h"
   22.50 -
   22.51 -using namespace SourceMod;
   22.52 -using namespace SourceHook;
   22.53 -
   22.54 -class CExtension;
   22.55 -
   22.56 -struct sm_extnative_t
   22.57 -{
   22.58 -	CExtension *owner;
   22.59 -	const sp_nativeinfo_t *info;
   22.60 -};
   22.61 -
   22.62 -class CExtension : 
   22.63 -	public IExtension,
   22.64 -	public CNativeOwner
   22.65 -{
   22.66 -	friend class CExtensionManager;
   22.67 -public:
   22.68 -	virtual ~CExtension();
   22.69 -public: //IExtension
   22.70 -	IExtensionInterface *GetAPI();
   22.71 -	const char *GetFilename();
   22.72 -	IdentityToken_t *GetIdentity();
   22.73 -	ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
   22.74 -	bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
   22.75 -	void FreeDependencyIterator(ITERATOR *iter);
   22.76 -	bool IsRunning(char *error, size_t maxlength);
   22.77 -public:
   22.78 -	void SetError(const char *error);
   22.79 -	void AddDependency(const IfaceInfo *pInfo);
   22.80 -	void AddChildDependent(CExtension *pOther, SMInterface *iface);
   22.81 -	void AddInterface(SMInterface *pInterface);
   22.82 -	void AddPlugin(CPlugin *pPlugin);
   22.83 -	void MarkAllLoaded();
   22.84 -	void AddLibrary(const char *library);
   22.85 -public:
   22.86 -	virtual bool Load(char *error, size_t maxlength);
   22.87 -	virtual bool IsLoaded() =0;
   22.88 -	virtual void Unload() =0;
   22.89 -protected:
   22.90 -	void Initialize(const char *filename, const char *path);
   22.91 -	bool PerformAPICheck(char *error, size_t maxlength);
   22.92 -	void CreateIdentity();
   22.93 -	void DestroyIdentity();
   22.94 -protected:
   22.95 -	IdentityToken_t *m_pIdentToken;
   22.96 -	IExtensionInterface *m_pAPI;
   22.97 -	String m_File;
   22.98 -	String m_Path;
   22.99 -	String m_Error;
  22.100 -	List<IfaceInfo> m_Deps;			/** Dependencies */
  22.101 -	List<IfaceInfo> m_ChildDeps;	/** Children who might depend on us */
  22.102 -	List<SMInterface *> m_Interfaces;
  22.103 -	List<String> m_Libraries;
  22.104 -	unsigned int unload_code;
  22.105 -	bool m_bFullyLoaded;
  22.106 -};
  22.107 -
  22.108 -class CLocalExtension : public CExtension
  22.109 -{
  22.110 -public:
  22.111 -	CLocalExtension(const char *filename);
  22.112 -public:
  22.113 -	bool Load(char *error, size_t maxlength);
  22.114 -	bool IsLoaded();
  22.115 -	void Unload();
  22.116 -	bool IsExternal();
  22.117 -private:
  22.118 -	PluginId m_PlId;
  22.119 -	ILibrary *m_pLib;
  22.120 -};
  22.121 -
  22.122 -class CRemoteExtension : public CExtension
  22.123 -{
  22.124 -public:
  22.125 -	CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path);
  22.126 -public:
  22.127 -	bool Load(char *error, size_t maxlength);
  22.128 -	bool IsLoaded();
  22.129 -	void Unload();
  22.130 -	bool IsExternal();
  22.131 -};
  22.132 -
  22.133 -class CExtensionManager : 
  22.134 -	public IExtensionManager,
  22.135 -	public SMGlobalClass,
  22.136 -	public IPluginsListener,
  22.137 -	public IRootConsoleCommand
  22.138 -{
  22.139 -public:
  22.140 -	CExtensionManager();
  22.141 -	~CExtensionManager();
  22.142 -public: //SMGlobalClass
  22.143 -	void OnSourceModAllInitialized();
  22.144 -	void OnSourceModShutdown();
  22.145 -public: //IExtensionManager
  22.146 -	IExtension *LoadExtension(const char *path, 
  22.147 -		char *error,
  22.148 -		size_t maxlength);
  22.149 -	bool UnloadExtension(IExtension *pExt);
  22.150 -	IExtension *FindExtensionByFile(const char *file);
  22.151 -	IExtension *FindExtensionByName(const char *ext);
  22.152 -	IExtension *LoadExternal(IExtensionInterface *pInterface,
  22.153 -		const char *filepath,
  22.154 -		const char *filename,
  22.155 -		char *error,
  22.156 -		size_t maxlength);
  22.157 -public: //IPluginsListener
  22.158 -	void OnPluginDestroyed(IPlugin *plugin);
  22.159 -public: //IRootConsoleCommand
  22.160 -	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
  22.161 -public:
  22.162 -	IExtension *LoadAutoExtension(const char *path);
  22.163 -	void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
  22.164 -	void AddInterface(IExtension *pOwner, SMInterface *pInterface);
  22.165 -	void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
  22.166 -	void MarkAllLoaded();
  22.167 -	void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
  22.168 -	void TryAutoload();
  22.169 -	void AddLibrary(IExtension *pSource, const char *library);
  22.170 -	bool LibraryExists(const char *library);
  22.171 -	void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
  22.172 -	void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
  22.173 -public:
  22.174 -	CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
  22.175 -	void Shutdown();
  22.176 -	CNativeOwner *GetNativeOwner(IExtension *pExt)
  22.177 -	{
  22.178 -		CExtension *p = (CExtension *)pExt;
  22.179 -		return p;
  22.180 -	}
  22.181 -private:
  22.182 -	CExtension *FindByOrder(unsigned int num);
  22.183 -private:
  22.184 -	List<CExtension *> m_Libs;
  22.185 -};
  22.186 -
  22.187 -extern CExtensionManager g_Extensions;
  22.188 -
  22.189 -#endif //_INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
    23.1 --- a/core/systems/ForwardSys.cpp	Mon Nov 24 08:25:36 2008 -0600
    23.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.3 @@ -1,751 +0,0 @@
    23.4 -/**
    23.5 - * vim: set ts=4 :
    23.6 - * =============================================================================
    23.7 - * SourceMod
    23.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    23.9 - * =============================================================================
   23.10 - *
   23.11 - * This program is free software; you can redistribute it and/or modify it under
   23.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   23.13 - * Free Software Foundation.
   23.14 - * 
   23.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   23.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   23.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   23.18 - * details.
   23.19 - *
   23.20 - * You should have received a copy of the GNU General Public License along with
   23.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   23.22 - *
   23.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   23.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   23.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   23.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   23.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   23.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   23.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   23.30 - * or <http://www.sourcemod.net/license.php>.
   23.31 - *
   23.32 - * Version: $Id$
   23.33 - */
   23.34 -
   23.35 -#include <assert.h>
   23.36 -#include <stdarg.h>
   23.37 -#include <string.h>
   23.38 -#include "ForwardSys.h"
   23.39 -#include "PluginSys.h"
   23.40 -#include "ShareSys.h"
   23.41 -#include "DebugReporter.h"
   23.42 -
   23.43 -CForwardManager g_Forwards;
   23.44 -
   23.45 -/**
   23.46 - * Genesis turns to its source, reduction occurs stepwise although the essence is all one.
   23.47 - * End of line.  FTL system check.
   23.48 - *
   23.49 - * :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
   23.50 - * VARARG FUNCTIONS:
   23.51 - * - Pushing no varargs
   23.52 - */
   23.53 -
   23.54 -// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
   23.55 -// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
   23.56 -
   23.57 -CForwardManager::~CForwardManager()
   23.58 -{
   23.59 -	CStack<CForward *>::iterator iter;
   23.60 -	for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
   23.61 -	{
   23.62 -		delete (*iter);
   23.63 -	}
   23.64 -	m_FreeForwards.popall();
   23.65 -}
   23.66 -
   23.67 -void CForwardManager::OnSourceModAllInitialized()
   23.68 -{
   23.69 -	g_PluginSys.AddPluginsListener(this);
   23.70 -	g_ShareSys.AddInterface(NULL, this);
   23.71 -}
   23.72 -
   23.73 -IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
   23.74 -{
   23.75 -	CForward *fwd;
   23.76 -	va_list ap;
   23.77 -	va_start(ap, types);
   23.78 -	
   23.79 -	fwd = CForward::CreateForward(name, et, num_params, types, ap);
   23.80 -
   23.81 -	va_end(ap);
   23.82 -
   23.83 -	if (fwd)
   23.84 -	{
   23.85 -		g_PluginSys.AddFunctionsToForward(name, fwd);
   23.86 -
   23.87 -		m_managed.push_back(fwd);
   23.88 -	}
   23.89 -
   23.90 -	return fwd;
   23.91 -}
   23.92 -
   23.93 -IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
   23.94 -{
   23.95 -	CForward *fwd;
   23.96 -	va_list ap;
   23.97 -	va_start(ap, types);
   23.98 -
   23.99 -	fwd = CForward::CreateForward(name, et, num_params, types, ap);
  23.100 -
  23.101 -	va_end(ap);
  23.102 -
  23.103 -	if (fwd)
  23.104 -	{
  23.105 -		m_unmanaged.push_back(fwd);
  23.106 -	}
  23.107 -
  23.108 -	return fwd;
  23.109 -}
  23.110 -
  23.111 -void CForwardManager::OnPluginLoaded(IPlugin *plugin)
  23.112 -{
  23.113 -	/* Attach any globally managed forwards */
  23.114 -	List<CForward *>::iterator iter;
  23.115 -	CForward *fwd;
  23.116 -
  23.117 -	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
  23.118 -	{
  23.119 -		fwd = (*iter);
  23.120 -		IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
  23.121 -		if (pFunc)
  23.122 -		{
  23.123 -			fwd->AddFunction(pFunc);
  23.124 -		}
  23.125 -	}
  23.126 -}
  23.127 -
  23.128 -void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
  23.129 -{
  23.130 -	List<CForward *>::iterator iter;
  23.131 -	CForward *fwd;
  23.132 -
  23.133 -	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
  23.134 -	{
  23.135 -		fwd = (*iter);
  23.136 -		fwd->RemoveFunctionsOfPlugin(plugin);
  23.137 -	}
  23.138 -
  23.139 -	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
  23.140 -	{
  23.141 -		fwd = (*iter);
  23.142 -		fwd->RemoveFunctionsOfPlugin(plugin);
  23.143 -	}
  23.144 -}
  23.145 -
  23.146 -IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
  23.147 -{
  23.148 -	List<CForward *>::iterator iter;
  23.149 -	CForward *fwd;
  23.150 -
  23.151 -	for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
  23.152 -	{
  23.153 -		fwd = (*iter);
  23.154 -		if (strcmp(fwd->GetForwardName(), name) == 0)
  23.155 -		{
  23.156 -			if (ifchng)
  23.157 -			{
  23.158 -				*ifchng = NULL;
  23.159 -			}
  23.160 -			return fwd;
  23.161 -		}
  23.162 -	}
  23.163 -
  23.164 -	for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
  23.165 -	{
  23.166 -		fwd = (*iter);
  23.167 -		if (strcmp(fwd->GetForwardName(), name) == 0)
  23.168 -		{
  23.169 -			if (ifchng)
  23.170 -			{
  23.171 -				*ifchng = fwd;
  23.172 -			}
  23.173 -			return fwd;
  23.174 -		}
  23.175 -	}
  23.176 -
  23.177 -	if (ifchng)
  23.178 -	{
  23.179 -		*ifchng = NULL;
  23.180 -	}
  23.181 -
  23.182 -	return NULL;
  23.183 -}
  23.184 -
  23.185 -void CForwardManager::ReleaseForward(IForward *forward)
  23.186 -{
  23.187 -	ForwardFree(static_cast<CForward *>(forward));
  23.188 -}
  23.189 -
  23.190 -void CForwardManager::ForwardFree(CForward *fwd)
  23.191 -{
  23.192 -    if (fwd == NULL)
  23.193 -    {
  23.194 -        return;
  23.195 -    }
  23.196 -
  23.197 -	m_FreeForwards.push(fwd);
  23.198 -	m_managed.remove(fwd);
  23.199 -}
  23.200 -
  23.201 -CForward *CForwardManager::ForwardMake()
  23.202 -{
  23.203 -	CForward *fwd;
  23.204 -	if (m_FreeForwards.empty())
  23.205 -	{
  23.206 -		fwd = new CForward;
  23.207 -	} else {
  23.208 -		fwd = m_FreeForwards.front();
  23.209 -		m_FreeForwards.pop();
  23.210 -	}
  23.211 -	return fwd;
  23.212 -}
  23.213 -
  23.214 -void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
  23.215 -{
  23.216 -	/* No longer used */
  23.217 -}
  23.218 -
  23.219 -/*************************************
  23.220 - * ACTUAL FORWARD API IMPLEMENTATION *
  23.221 - *************************************/
  23.222 -
  23.223 -CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
  23.224 -{
  23.225 -	ParamType _types[SP_MAX_EXEC_PARAMS];
  23.226 -
  23.227 -	if (num_params > SP_MAX_EXEC_PARAMS)
  23.228 -	{
  23.229 -		return NULL;
  23.230 -	}
  23.231 -	
  23.232 -	if (types == NULL && num_params)
  23.233 -	{
  23.234 -		for (unsigned int i=0; i<num_params; i++)
  23.235 -		{
  23.236 -			_types[i] = (ParamType)va_arg(ap, int);
  23.237 -			if (_types[i] == Param_VarArgs && (i != num_params - 1))
  23.238 -			{
  23.239 -				return NULL;
  23.240 -			}
  23.241 -		}
  23.242 -		types = _types;
  23.243 -	} else {
  23.244 -		for (unsigned int i=0; i<num_params; i++)
  23.245 -		{
  23.246 -			_types[i] = types[i];
  23.247 -			if (types[i] == Param_VarArgs && (i != num_params - 1))
  23.248 -			{
  23.249 -				return NULL;
  23.250 -			}
  23.251 -		}
  23.252 -	}
  23.253 -
  23.254 -	/* First parameter can never be varargs */
  23.255 -	if (num_params && _types[0] == Param_VarArgs)
  23.256 -	{
  23.257 -		return NULL;
  23.258 -	}
  23.259 -
  23.260 -	CForward *pForward = g_Forwards.ForwardMake();
  23.261 -	pForward->m_curparam = 0;
  23.262 -	pForward->m_ExecType = et;
  23.263 -	snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
  23.264 -	
  23.265 -	for (unsigned int i=0; i<num_params; i++)
  23.266 -	{
  23.267 -		pForward->m_types[i] = _types[i];
  23.268 -	}
  23.269 -
  23.270 -	if (num_params && _types[num_params-1] == Param_VarArgs)
  23.271 -	{
  23.272 -		pForward->m_varargs = num_params--;
  23.273 -	} else {
  23.274 -		pForward->m_varargs = false;
  23.275 -	}
  23.276 -
  23.277 -	pForward->m_numparams = num_params;
  23.278 -	pForward->m_errstate = SP_ERROR_NONE;
  23.279 -
  23.280 -	pForward->m_functions.clear();
  23.281 -
  23.282 -	return pForward;
  23.283 -}
  23.284 -
  23.285 -int CForward::Execute(cell_t *result, IForwardFilter *filter)
  23.286 -{
  23.287 -	if (m_errstate)
  23.288 -	{
  23.289 -		int err = m_errstate;
  23.290 -		Cancel();
  23.291 -		return err;
  23.292 -	}
  23.293 -
  23.294 -	FuncIter iter = m_functions.begin();
  23.295 -	IPluginFunction *func;
  23.296 -	cell_t cur_result = 0;
  23.297 -	cell_t high_result = 0;
  23.298 -	cell_t low_result = 0;
  23.299 -	int err;
  23.300 -	unsigned int failed=0, success=0;
  23.301 -	unsigned int num_params = m_curparam;
  23.302 -	FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
  23.303 -	FwdParamInfo *param;
  23.304 -	ParamType type;
  23.305 -
  23.306 -	/* Save local, reset */
  23.307 -	memcpy(temp_info, m_params, sizeof(m_params));
  23.308 -	m_curparam = 0;
  23.309 -
  23.310 -	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
  23.311 -	{
  23.312 -		func = (*iter);
  23.313 -
  23.314 -		for (unsigned int i=0; i<num_params; i++)
  23.315 -		{
  23.316 -			int err = SP_ERROR_PARAM;
  23.317 -			param = &temp_info[i];
  23.318 -
  23.319 -			if (i >= m_numparams || m_types[i] == Param_Any)
  23.320 -			{
  23.321 -				type = param->pushedas;
  23.322 -			}
  23.323 -			else
  23.324 -			{
  23.325 -				type = m_types[i];
  23.326 -			}
  23.327 -
  23.328 -			if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
  23.329 -			{
  23.330 -				/* If we're byref or we're vararg, we always push everything by ref.
  23.331 -				 * Even if they're byval, we must push them byref.
  23.332 -				 */
  23.333 -				if (type == Param_String)
  23.334 -				{
  23.335 -					err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
  23.336 -				}
  23.337 -				else if (type == Param_Float || type == Param_Cell)
  23.338 -				{
  23.339 -					err = func->PushCellByRef(&param->val); 
  23.340 -				}
  23.341 -				else
  23.342 -				{
  23.343 -					err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
  23.344 -					assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
  23.345 -				}
  23.346 -			}
  23.347 -			else
  23.348 -			{
  23.349 -				/* If we're not byref or not vararg, our job is a bit easier. */
  23.350 -				assert(type == Param_Cell || type == Param_Float);
  23.351 -				err = func->PushCell(param->val);
  23.352 -			}
  23.353 -
  23.354 -			if (err != SP_ERROR_NONE)
  23.355 -			{
  23.356 -				g_DbgReporter.GenerateError(func->GetParentContext(), 
  23.357 -					func->GetFunctionID(), 
  23.358 -					err, 
  23.359 -					"Failed to push parameter while executing forward");
  23.360 -				continue;
  23.361 -			}
  23.362 -		}
  23.363 -		
  23.364 -		/* Call the function and deal with the return value. */
  23.365 -		if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
  23.366 -		{
  23.367 -			failed++;
  23.368 -		}
  23.369 -		else
  23.370 -		{
  23.371 -			success++;
  23.372 -			switch (m_ExecType)
  23.373 -			{
  23.374 -			case ET_Event:
  23.375 -				{
  23.376 -					if (cur_result > high_result)
  23.377 -					{
  23.378 -						high_result = cur_result;
  23.379 -					}
  23.380 -					break;
  23.381 -				}
  23.382 -			case ET_Hook:
  23.383 -				{
  23.384 -					if (cur_result > high_result)
  23.385 -					{
  23.386 -						high_result = cur_result;
  23.387 -						if ((ResultType)high_result == Pl_Stop)
  23.388 -						{
  23.389 -							goto done;
  23.390 -						}
  23.391 -					}
  23.392 -					break;
  23.393 -				}
  23.394 -			case ET_LowEvent:
  23.395 -				{
  23.396 -					/* Check if the current result is the lowest so far (or if it's the first result) */
  23.397 -					if (cur_result < low_result || success == 1)
  23.398 -					{
  23.399 -						low_result = cur_result;
  23.400 -					}
  23.401 -					break;
  23.402 -				}
  23.403 -			default:
  23.404 -				{
  23.405 -					break;
  23.406 -				}
  23.407 -			}
  23.408 -		}
  23.409 -	}
  23.410 -
  23.411 -done:
  23.412 -
  23.413 -	if (success)
  23.414 -	{
  23.415 -		switch (m_ExecType)
  23.416 -		{
  23.417 -		case ET_Ignore:
  23.418 -			{
  23.419 -				cur_result = 0;
  23.420 -				break;
  23.421 -			}
  23.422 -		case ET_Event:
  23.423 -		case ET_Hook:
  23.424 -			{
  23.425 -				cur_result = high_result;
  23.426 -				break;
  23.427 -			}
  23.428 -		case ET_LowEvent:
  23.429 -			{
  23.430 -				cur_result = low_result;
  23.431 -				break;
  23.432 -			}
  23.433 -		default:
  23.434 -			{
  23.435 -				break;
  23.436 -			}
  23.437 -		}
  23.438 -
  23.439 -		if (result)
  23.440 -		{
  23.441 -			*result = cur_result;
  23.442 -		}
  23.443 -	}
  23.444 -
  23.445 -	return SP_ERROR_NONE;
  23.446 -}
  23.447 -
  23.448 -int CForward::PushCell(cell_t cell)
  23.449 -{
  23.450 -	if (m_curparam < m_numparams)
  23.451 -	{
  23.452 -		if (m_types[m_curparam] == Param_Any)
  23.453 -		{
  23.454 -			m_params[m_curparam].pushedas = Param_Cell;
  23.455 -		} else if (m_types[m_curparam] != Param_Cell) {
  23.456 -			return SetError(SP_ERROR_PARAM);
  23.457 -		}
  23.458 -	} else {
  23.459 -		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
  23.460 -		{
  23.461 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.462 -		}
  23.463 -		m_params[m_curparam].pushedas = Param_Cell;
  23.464 -	}
  23.465 -
  23.466 -	m_params[m_curparam++].val = cell;
  23.467 -
  23.468 -	return SP_ERROR_NONE;
  23.469 -}
  23.470 -
  23.471 -int CForward::PushFloat(float number)
  23.472 -{
  23.473 -	if (m_curparam < m_numparams)
  23.474 -	{
  23.475 -		if (m_types[m_curparam] == Param_Any)
  23.476 -		{
  23.477 -			m_params[m_curparam].pushedas = Param_Float;
  23.478 -		} else if (m_types[m_curparam] != Param_Float) {
  23.479 -			return SetError(SP_ERROR_PARAM);
  23.480 -		}
  23.481 -	} else {
  23.482 -		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
  23.483 -		{
  23.484 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.485 -		}
  23.486 -		m_params[m_curparam].pushedas = Param_Float;
  23.487 -	}
  23.488 -
  23.489 -	m_params[m_curparam++].val = *(cell_t *)&number;
  23.490 -
  23.491 -	return SP_ERROR_NONE;
  23.492 -}
  23.493 -
  23.494 -int CForward::PushCellByRef(cell_t *cell, int flags)
  23.495 -{
  23.496 -	if (m_curparam < m_numparams)
  23.497 -	{
  23.498 -		if (m_types[m_curparam] == Param_Any)
  23.499 -		{
  23.500 -			m_params[m_curparam].pushedas = Param_CellByRef;
  23.501 -		} else if (m_types[m_curparam] != Param_CellByRef) {
  23.502 -			return SetError(SP_ERROR_PARAM);
  23.503 -		}
  23.504 -	} else {
  23.505 -		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
  23.506 -		{
  23.507 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.508 -		}
  23.509 -		m_params[m_curparam].pushedas = Param_CellByRef;
  23.510 -	}
  23.511 -
  23.512 -	_Int_PushArray(cell, 1, flags);
  23.513 -	m_curparam++;
  23.514 -
  23.515 -	return SP_ERROR_NONE;
  23.516 -}
  23.517 -
  23.518 -int CForward::PushFloatByRef(float *num, int flags)
  23.519 -{
  23.520 -	if (m_curparam < m_numparams)
  23.521 -	{
  23.522 -		if (m_types[m_curparam] == Param_Any)
  23.523 -		{
  23.524 -			m_params[m_curparam].pushedas = Param_FloatByRef;
  23.525 -		} else if (m_types[m_curparam] != Param_FloatByRef) {
  23.526 -			return SetError(SP_ERROR_PARAM);
  23.527 -		}
  23.528 -	} else {
  23.529 -		if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
  23.530 -		{
  23.531 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.532 -		}
  23.533 -		m_params[m_curparam].pushedas = Param_FloatByRef;
  23.534 -	}
  23.535 -
  23.536 -	_Int_PushArray((cell_t *)num, 1, flags);
  23.537 -	m_curparam++;
  23.538 -
  23.539 -	return SP_ERROR_NONE;
  23.540 -}
  23.541 -
  23.542 -void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
  23.543 -{
  23.544 -	m_params[m_curparam].byref.cells = cells;
  23.545 -	m_params[m_curparam].byref.flags = flags;
  23.546 -	m_params[m_curparam].byref.orig_addr = inarray;
  23.547 -}
  23.548 -
  23.549 -int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
  23.550 -{
  23.551 -	/* We don't allow this here */
  23.552 -	if (!inarray)
  23.553 -	{
  23.554 -		return SetError(SP_ERROR_PARAM);
  23.555 -	}
  23.556 -
  23.557 -	if (m_curparam < m_numparams)
  23.558 -	{
  23.559 -		if (m_types[m_curparam] == Param_Any)
  23.560 -		{
  23.561 -			m_params[m_curparam].pushedas = Param_Array;
  23.562 -		} else if (m_types[m_curparam] != Param_Array) {
  23.563 -			return SetError(SP_ERROR_PARAM);
  23.564 -		}
  23.565 -	} else {
  23.566 -		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
  23.567 -		{
  23.568 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.569 -		}
  23.570 -		m_params[m_curparam].pushedas = Param_Array;
  23.571 -	}
  23.572 -
  23.573 -	_Int_PushArray(inarray, cells, flags);
  23.574 -
  23.575 -	m_curparam++;
  23.576 -
  23.577 -	return SP_ERROR_NONE;
  23.578 -}
  23.579 -
  23.580 -void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
  23.581 -{
  23.582 -	m_params[m_curparam].byref.cells = cells;	/* Notice this contains the char count not cell count */
  23.583 -	m_params[m_curparam].byref.flags = cp_flags;
  23.584 -	m_params[m_curparam].byref.orig_addr = inarray;
  23.585 -	m_params[m_curparam].byref.sz_flags = sz_flags;
  23.586 -}
  23.587 -
  23.588 -int CForward::PushString(const char *string)
  23.589 -{
  23.590 -	if (m_curparam < m_numparams)
  23.591 -	{
  23.592 -		if (m_types[m_curparam] == Param_Any)
  23.593 -		{
  23.594 -			m_params[m_curparam].pushedas = Param_String;
  23.595 -		} else if (m_types[m_curparam] != Param_String) {
  23.596 -			return SetError(SP_ERROR_PARAM);
  23.597 -		}
  23.598 -	} else {
  23.599 -		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
  23.600 -		{
  23.601 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.602 -		}
  23.603 -		m_params[m_curparam].pushedas = Param_String;
  23.604 -	}
  23.605 -
  23.606 -	_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
  23.607 -	m_curparam++;
  23.608 -
  23.609 -	return SP_ERROR_NONE;
  23.610 -}
  23.611 -
  23.612 -int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
  23.613 -{
  23.614 -	if (m_curparam < m_numparams)
  23.615 -	{
  23.616 -		if (m_types[m_curparam] == Param_Any)
  23.617 -		{
  23.618 -			m_params[m_curparam].pushedas = Param_String;
  23.619 -		} else if (m_types[m_curparam] != Param_String) {
  23.620 -			return SetError(SP_ERROR_PARAM);
  23.621 -		}
  23.622 -	} else {
  23.623 -		if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
  23.624 -		{
  23.625 -			return SetError(SP_ERROR_PARAMS_MAX);
  23.626 -		}
  23.627 -		m_params[m_curparam].pushedas = Param_String;
  23.628 -	}
  23.629 -
  23.630 -	_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
  23.631 -	m_curparam++;
  23.632 -
  23.633 -	return SP_ERROR_NONE;
  23.634 -}
  23.635 -
  23.636 -void CForward::Cancel()
  23.637 -{
  23.638 -	if (!m_curparam)
  23.639 -	{
  23.640 -		return;
  23.641 -	}
  23.642 -
  23.643 -	m_curparam = 0;
  23.644 -	m_errstate = SP_ERROR_NONE;
  23.645 -}
  23.646 -
  23.647 -bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
  23.648 -{
  23.649 -	IPluginFunction *pFunc = pContext->GetFunctionById(index);
  23.650 -
  23.651 -	if (!pFunc)
  23.652 -	{
  23.653 -		return false;
  23.654 -	}
  23.655 -
  23.656 -	return AddFunction(pFunc);
  23.657 -}
  23.658 -
  23.659 -bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
  23.660 -{
  23.661 -	IPluginFunction *pFunc = pContext->GetFunctionById(index);
  23.662 -
  23.663 -	if (!pFunc)
  23.664 -	{
  23.665 -		return false;
  23.666 -	}
  23.667 -
  23.668 -	return RemoveFunction(pFunc);
  23.669 -}
  23.670 -
  23.671 -bool CForward::RemoveFunction(IPluginFunction *func)
  23.672 -{
  23.673 -	bool found = false;
  23.674 -	FuncIter iter;
  23.675 -	List<IPluginFunction *> *lst;
  23.676 -
  23.677 -	if (func->IsRunnable())
  23.678 -	{
  23.679 -		lst = &m_functions;
  23.680 -	} else {
  23.681 -		lst = &m_paused;
  23.682 -	}
  23.683 -
  23.684 -	for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
  23.685 -	{
  23.686 -		if ((*iter) == func)
  23.687 -		{
  23.688 -			found = true;
  23.689 -			lst->erase(iter);
  23.690 -			break;
  23.691 -		}
  23.692 -	}
  23.693 -
  23.694 -	/* Cancel a call, if any */
  23.695 -	if (found || m_curparam)
  23.696 -	{
  23.697 -		func->Cancel();
  23.698 -	}
  23.699 -
  23.700 -	return found;
  23.701 -}
  23.702 -
  23.703 -unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
  23.704 -{
  23.705 -	FuncIter iter;
  23.706 -	IPluginFunction *func;
  23.707 -	unsigned int removed = 0;
  23.708 -	IPluginContext *pContext = plugin->GetBaseContext();
  23.709 -	for (iter=m_functions.begin(); iter!=m_functions.end();)
  23.710 -	{
  23.711 -		func = (*iter);
  23.712 -		if (func->GetParentContext() == pContext)
  23.713 -		{
  23.714 -			iter = m_functions.erase(iter);
  23.715 -			removed++;
  23.716 -		} else {
  23.717 -			iter++;
  23.718 -		}
  23.719 -	}
  23.720 -
  23.721 -	return removed;
  23.722 -}
  23.723 -
  23.724 -bool CForward::AddFunction(IPluginFunction *func)
  23.725 -{
  23.726 -	if (m_curparam)
  23.727 -	{
  23.728 -		return false;
  23.729 -	}
  23.730 -
  23.731 -	if (func->IsRunnable())
  23.732 -	{
  23.733 -		m_functions.push_back(func);
  23.734 -	} else {
  23.735 -		m_paused.push_back(func);
  23.736 -	}
  23.737 -
  23.738 -	return true;
  23.739 -}
  23.740 -
  23.741 -const char *CForward::GetForwardName()
  23.742 -{
  23.743 -	return m_name;
  23.744 -}
  23.745 -
  23.746 -unsigned int CForward::GetFunctionCount()
  23.747 -{
  23.748 -	return m_functions.size();
  23.749 -}
  23.750 -
  23.751 -ExecType CForward::GetExecType()
  23.752 -{
  23.753 -	return m_ExecType;
  23.754 -}
    24.1 --- a/core/systems/ForwardSys.h	Mon Nov 24 08:25:36 2008 -0600
    24.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.3 @@ -1,158 +0,0 @@
    24.4 -/**
    24.5 - * vim: set ts=4 :
    24.6 - * =============================================================================
    24.7 - * SourceMod
    24.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    24.9 - * =============================================================================
   24.10 - *
   24.11 - * This program is free software; you can redistribute it and/or modify it under
   24.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   24.13 - * Free Software Foundation.
   24.14 - * 
   24.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   24.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   24.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   24.18 - * details.
   24.19 - *
   24.20 - * You should have received a copy of the GNU General Public License along with
   24.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   24.22 - *
   24.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   24.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   24.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   24.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   24.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   24.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   24.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   24.30 - * or <http://www.sourcemod.net/license.php>.
   24.31 - *
   24.32 - * Version: $Id$
   24.33 - */
   24.34 -
   24.35 -#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
   24.36 -#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
   24.37 -
   24.38 -#include <IForwardSys.h>
   24.39 -#include <IPluginSys.h>
   24.40 -#include "sm_globals.h"
   24.41 -#include <sh_list.h>
   24.42 -#include <sh_stack.h>
   24.43 -#include "sourcemod.h"
   24.44 -
   24.45 -using namespace SourceHook;
   24.46 -
   24.47 -typedef List<IPluginFunction *>::iterator FuncIter;
   24.48 -
   24.49 -/* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
   24.50 -#define FORWARDS_NAME_MAX		64
   24.51 -
   24.52 -struct ByrefInfo
   24.53 -{
   24.54 -	unsigned int cells;
   24.55 -	cell_t *orig_addr;
   24.56 -	int flags;
   24.57 -	int sz_flags;
   24.58 -};
   24.59 -
   24.60 -struct FwdParamInfo
   24.61 -{
   24.62 -	cell_t val;
   24.63 -	ByrefInfo byref;
   24.64 -	ParamType pushedas;
   24.65 -};
   24.66 -
   24.67 -class CForward : public IChangeableForward
   24.68 -{
   24.69 -public: //ICallable
   24.70 -	virtual int PushCell(cell_t cell);
   24.71 -	virtual int PushCellByRef(cell_t *cell, int flags);
   24.72 -	virtual int PushFloat(float number);
   24.73 -	virtual int PushFloatByRef(float *number, int flags);
   24.74 -	virtual int PushArray(cell_t *inarray, unsigned int cells, int flags);
   24.75 -	virtual int PushString(const char *string);
   24.76 -	virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
   24.77 -	virtual void Cancel();
   24.78 -public: //IForward
   24.79 -	virtual const char *GetForwardName();
   24.80 -	virtual unsigned int GetFunctionCount();
   24.81 -	virtual ExecType GetExecType();
   24.82 -	virtual int Execute(cell_t *result, IForwardFilter *filter);
   24.83 -public: //IChangeableForward
   24.84 -	virtual bool RemoveFunction(IPluginFunction *func);
   24.85 -	virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
   24.86 -	virtual bool AddFunction(IPluginFunction *func);
   24.87 -	virtual bool AddFunction(IPluginContext *ctx, funcid_t index);
   24.88 -	virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
   24.89 -public:
   24.90 -	static CForward *CreateForward(const char *name, 
   24.91 -								   ExecType et, 
   24.92 -								   unsigned int num_params, 
   24.93 -								   const ParamType *types, 
   24.94 -								   va_list ap);
   24.95 -private:
   24.96 -	void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
   24.97 -	void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
   24.98 -	inline int SetError(int err)
   24.99 -	{
  24.100 -		m_errstate = err;
  24.101 -		return err;
  24.102 -	}
  24.103 -protected:
  24.104 -	/* :TODO: I want a caching list type here.
  24.105 -	 * Destroying these things and using new/delete for their members feels bad.
  24.106 -	 */
  24.107 -	mutable List<IPluginFunction *> m_functions;
  24.108 -	mutable List<IPluginFunction *> m_paused;
  24.109 -
  24.110 -	/* Type and name information */
  24.111 -	FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
  24.112 -	ParamType m_types[SP_MAX_EXEC_PARAMS];
  24.113 -	char m_name[FORWARDS_NAME_MAX+1];
  24.114 -	unsigned int m_numparams;
  24.115 -	unsigned int m_varargs;
  24.116 -	ExecType m_ExecType;
  24.117 -
  24.118 -	/* State information */
  24.119 -	unsigned int m_curparam;
  24.120 -	int m_errstate;
  24.121 -};
  24.122 -
  24.123 -class CForwardManager : 
  24.124 -	public IForwardManager,
  24.125 -	public IPluginsListener,
  24.126 -	public SMGlobalClass
  24.127 -{
  24.128 -	friend class CForward;
  24.129 -public:
  24.130 -	~CForwardManager();
  24.131 -public: //IForwardManager
  24.132 -	IForward *CreateForward(const char *name, 
  24.133 -		ExecType et, 
  24.134 -		unsigned int num_params, 
  24.135 -		const ParamType *types, 
  24.136 -		...);
  24.137 -	IChangeableForward *CreateForwardEx(const char *name, 
  24.138 -		ExecType et, 
  24.139 -		int num_params, 
  24.140 -		const ParamType *types, 
  24.141 -		...);
  24.142 -	IForward *FindForward(const char *name, IChangeableForward **ifchng);
  24.143 -	void ReleaseForward(IForward *forward);
  24.144 -public: //IPluginsListener
  24.145 -	void OnPluginLoaded(IPlugin *plugin);
  24.146 -	void OnPluginUnloaded(IPlugin *plugin);
  24.147 -	void OnPluginPauseChange(IPlugin *plugin, bool paused);
  24.148 -public: //SMGlobalClass
  24.149 -	void OnSourceModAllInitialized();
  24.150 -protected:
  24.151 -	CForward *ForwardMake();
  24.152 -	void ForwardFree(CForward *fwd);
  24.153 -private:
  24.154 -	CStack<CForward *> m_FreeForwards;
  24.155 -	List<CForward *> m_managed;
  24.156 -	List<CForward *> m_unmanaged;
  24.157 -};
  24.158 -
  24.159 -extern CForwardManager g_Forwards;
  24.160 -
  24.161 -#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
    25.1 --- a/core/systems/HandleSys.cpp	Mon Nov 24 08:25:36 2008 -0600
    25.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.3 @@ -1,1076 +0,0 @@
    25.4 -/**
    25.5 - * vim: set ts=4 :
    25.6 - * =============================================================================
    25.7 - * SourceMod
    25.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    25.9 - * =============================================================================
   25.10 - *
   25.11 - * This program is free software; you can redistribute it and/or modify it under
   25.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   25.13 - * Free Software Foundation.
   25.14 - * 
   25.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   25.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   25.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   25.18 - * details.
   25.19 - *
   25.20 - * You should have received a copy of the GNU General Public License along with
   25.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   25.22 - *
   25.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   25.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   25.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   25.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   25.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   25.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   25.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   25.30 - * or <http://www.sourcemod.net/license.php>.
   25.31 - *
   25.32 - * Version: $Id$
   25.33 - */
   25.34 -
   25.35 -#include "HandleSys.h"
   25.36 -#include "ShareSys.h"
   25.37 -#include "PluginSys.h"
   25.38 -#include "ExtensionSys.h"
   25.39 -#include "Logger.h"
   25.40 -#include <assert.h>
   25.41 -#include <string.h>
   25.42 -#include "sm_stringutil.h"
   25.43 -
   25.44 -HandleSystem g_HandleSys;
   25.45 -
   25.46 -QHandle *ignore_handle;
   25.47 -
   25.48 -inline HandleType_t TypeParent(HandleType_t type)
   25.49 -{
   25.50 -	return (type & ~HANDLESYS_SUBTYPE_MASK);
   25.51 -}
   25.52 -
   25.53 -inline HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index)
   25.54 -{
   25.55 -	return g_HandleSys.GetHandle(token->ident, g_ShareSys.GetIdentRoot(), &ignore_handle, index);
   25.56 -}
   25.57 -
   25.58 -HandleSystem::HandleSystem()
   25.59 -{
   25.60 -	m_Handles = new QHandle[HANDLESYS_MAX_HANDLES + 1];
   25.61 -	memset(m_Handles, 0, sizeof(QHandle) * (HANDLESYS_MAX_HANDLES + 1));
   25.62 -
   25.63 -	m_Types = new QHandleType[HANDLESYS_TYPEARRAY_SIZE];
   25.64 -	memset(m_Types, 0, sizeof(QHandleType) * HANDLESYS_TYPEARRAY_SIZE);
   25.65 -
   25.66 -	m_TypeLookup = sm_trie_create();
   25.67 -	m_strtab = new BaseStringTable(512);
   25.68 -
   25.69 -	m_TypeTail = 0;
   25.70 -}
   25.71 -
   25.72 -HandleSystem::~HandleSystem()
   25.73 -{
   25.74 -	delete [] m_Handles;
   25.75 -	delete [] m_Types;
   25.76 -	sm_trie_destroy(m_TypeLookup);
   25.77 -	delete m_strtab;
   25.78 -}
   25.79 -
   25.80 -
   25.81 -HandleType_t HandleSystem::CreateType(const char *name, 
   25.82 -									  IHandleTypeDispatch *dispatch, 
   25.83 -									  HandleType_t parent, 
   25.84 -									  const TypeAccess *typeAccess, 
   25.85 -									  const HandleAccess *hndlAccess, 
   25.86 -									  IdentityToken_t *ident,
   25.87 -									  HandleError *err)
   25.88 -{
   25.89 -	if (!dispatch)
   25.90 -	{
   25.91 -		if (err)
   25.92 -		{
   25.93 -			*err = HandleError_Parameter;
   25.94 -		}
   25.95 -		return 0;
   25.96 -	}
   25.97 -
   25.98 -	if (typeAccess && typeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
   25.99 -	{
  25.100 -		if (err)
  25.101 -		{
  25.102 -			*err = HandleError_Version;
  25.103 -		}
  25.104 -		return 0;
  25.105 -	}
  25.106 -
  25.107 -	if (hndlAccess && hndlAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
  25.108 -	{
  25.109 -		if (err)
  25.110 -		{
  25.111 -			*err = HandleError_Version;
  25.112 -		}
  25.113 -		return 0;
  25.114 -	}
  25.115 -
  25.116 -	bool isChild = false;
  25.117 -
  25.118 -	if (parent != 0)
  25.119 -	{
  25.120 -		isChild = true;
  25.121 -		if (parent & HANDLESYS_SUBTYPE_MASK)
  25.122 -		{
  25.123 -			if (err)
  25.124 -			{
  25.125 -				*err = HandleError_NoInherit;
  25.126 -			}
  25.127 -			return 0;
  25.128 -		}
  25.129 -		if (parent >= HANDLESYS_TYPEARRAY_SIZE
  25.130 -			|| m_Types[parent].dispatch == NULL)
  25.131 -		{
  25.132 -			if (err)
  25.133 -			{
  25.134 -				*err = HandleError_Parameter;
  25.135 -			}
  25.136 -			return 0;
  25.137 -		}
  25.138 -		if (m_Types[parent].typeSec.access[HTypeAccess_Inherit] == false
  25.139 -			&& (m_Types[parent].typeSec.ident != ident))
  25.140 -		{
  25.141 -			if (err)
  25.142 -			{
  25.143 -				*err = HandleError_Access;
  25.144 -			}
  25.145 -			return 0;
  25.146 -		}
  25.147 -	}
  25.148 -
  25.149 -	if (name && name[0] != '\0')
  25.150 -	{
  25.151 -		if (sm_trie_retrieve(m_TypeLookup, name, NULL))
  25.152 -		{
  25.153 -			if (err)
  25.154 -			{
  25.155 -				*err = HandleError_Parameter;
  25.156 -			}
  25.157 -			return 0;
  25.158 -		}
  25.159 -	}
  25.160 -
  25.161 -	unsigned int index;
  25.162 -
  25.163 -	if (isChild)
  25.164 -	{
  25.165 -		QHandleType *pParent = &m_Types[parent];
  25.166 -		if (pParent->children >= HANDLESYS_MAX_SUBTYPES)
  25.167 -		{
  25.168 -			if (err)
  25.169 -			{
  25.170 -				*err = HandleError_Limit;
  25.171 -			}
  25.172 -			return 0;
  25.173 -		}
  25.174 -		index = 0;
  25.175 -		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
  25.176 -		{
  25.177 -			if (m_Types[parent + i].dispatch == NULL)
  25.178 -			{
  25.179 -				index = parent + i;
  25.180 -				break;
  25.181 -			}
  25.182 -		}
  25.183 -		if (!index)
  25.184 -		{
  25.185 -			if (err)
  25.186 -			{
  25.187 -				*err = HandleError_Limit;
  25.188 -			}
  25.189 -			return 0;
  25.190 -		}
  25.191 -		pParent->children++;
  25.192 -	} else {
  25.193 -		if (m_FreeTypes == 0)
  25.194 -		{
  25.195 -			/* Reserve another index */
  25.196 -			if (m_TypeTail >= HANDLESYS_TYPEARRAY_SIZE)
  25.197 -			{
  25.198 -				if (err)
  25.199 -				{
  25.200 -					*err = HandleError_Limit;
  25.201 -				}
  25.202 -				return 0;
  25.203 -			} else {
  25.204 -				m_TypeTail += (HANDLESYS_MAX_SUBTYPES + 1);
  25.205 -				index = m_TypeTail;
  25.206 -			}
  25.207 -		} else {
  25.208 -			/* The "free array" is compacted into the normal array for easiness */
  25.209 -			index = m_Types[m_FreeTypes--].freeID;
  25.210 -		}
  25.211 -	}
  25.212 -
  25.213 -	QHandleType *pType = &m_Types[index];
  25.214 -	
  25.215 -	pType->dispatch = dispatch;
  25.216 -	if (name && name[0] != '\0')
  25.217 -	{
  25.218 -		pType->nameIdx = m_strtab->AddString(name);
  25.219 -		sm_trie_insert(m_TypeLookup, name, (void *)pType);
  25.220 -	} else {
  25.221 -		pType->nameIdx = -1;
  25.222 -	}
  25.223 -
  25.224 -	pType->opened = 0;
  25.225 -
  25.226 -	if (typeAccess)
  25.227 -	{
  25.228 -		pType->typeSec = *typeAccess;
  25.229 -	} else {
  25.230 -		InitAccessDefaults(&pType->typeSec, NULL);
  25.231 -		pType->typeSec.ident = ident;
  25.232 -	}
  25.233 -
  25.234 -	if (hndlAccess)
  25.235 -	{
  25.236 -		pType->hndlSec = *hndlAccess;
  25.237 -	} else {
  25.238 -		InitAccessDefaults(NULL, &pType->hndlSec);
  25.239 -	}
  25.240 -
  25.241 -	if (!isChild)
  25.242 -	{
  25.243 -		pType->children = 0;
  25.244 -	}
  25.245 -
  25.246 -	return index;
  25.247 -}
  25.248 -
  25.249 -bool HandleSystem::FindHandleType(const char *name, HandleType_t *type)
  25.250 -{
  25.251 -	QHandleType *_type;
  25.252 -
  25.253 -	if (!sm_trie_retrieve(m_TypeLookup, name, (void **)&_type))
  25.254 -	{
  25.255 -		return false;
  25.256 -	}
  25.257 -
  25.258 -	unsigned int offset = _type - m_Types;
  25.259 -
  25.260 -	if (type)
  25.261 -	{
  25.262 -		*type = offset;
  25.263 -	}
  25.264 -
  25.265 -	return true;
  25.266 -}
  25.267 -
  25.268 -HandleError HandleSystem::TryAllocHandle(unsigned int *handle)
  25.269 -{
  25.270 -	if (m_FreeHandles == 0)
  25.271 -	{
  25.272 -		if (m_HandleTail >= HANDLESYS_MAX_HANDLES)
  25.273 -		{
  25.274 -			return HandleError_Limit;;
  25.275 -		}
  25.276 -		*handle = ++m_HandleTail;
  25.277 -	}
  25.278 -	else
  25.279 -	{
  25.280 -		*handle = m_Handles[m_FreeHandles--].freeID;
  25.281 -	}
  25.282 -
  25.283 -	return HandleError_None;
  25.284 -}
  25.285 -
  25.286 -HandleError HandleSystem::MakePrimHandle(HandleType_t type, 
  25.287 -						   QHandle **in_pHandle, 
  25.288 -						   unsigned int *in_index, 
  25.289 -						   Handle_t *in_handle,
  25.290 -						   IdentityToken_t *owner,
  25.291 -						   bool identity)
  25.292 -{
  25.293 -	HandleError err;
  25.294 -	unsigned int owner_index = 0;
  25.295 -
  25.296 -	if (owner && (IdentityHandle(owner, &owner_index) != HandleError_None))
  25.297 -	{
  25.298 -		return HandleError_Identity;
  25.299 -	}
  25.300 -
  25.301 -	unsigned int handle;
  25.302 -	if ((err = TryAllocHandle(&handle)) != HandleError_None)
  25.303 -	{
  25.304 -		if (!TryAndFreeSomeHandles()
  25.305 -			|| (err = TryAllocHandle(&handle)) != HandleError_None)
  25.306 -		{
  25.307 -			return err;
  25.308 -		}
  25.309 -	}
  25.310 -
  25.311 -	QHandle *pHandle = &m_Handles[handle];
  25.312 -	
  25.313 -	assert(pHandle->set == false);
  25.314 -
  25.315 -	if (++m_HSerial >= HANDLESYS_MAX_SERIALS)
  25.316 -	{
  25.317 -		m_HSerial = 1;
  25.318 -	}
  25.319 -
  25.320 -	/* Set essential information */
  25.321 -	pHandle->set = identity ? HandleSet_Identity : HandleSet_Used;
  25.322 -	pHandle->refcount = 1;
  25.323 -	pHandle->type = type;
  25.324 -	pHandle->serial = m_HSerial;
  25.325 -	pHandle->owner = owner;
  25.326 -	pHandle->ch_next = 0;
  25.327 -	pHandle->access_special = false;
  25.328 -	pHandle->is_destroying = false;
  25.329 -
  25.330 -	/* Create the hash value */
  25.331 -	Handle_t hash = pHandle->serial;
  25.332 -	hash <<= 16;
  25.333 -	hash |= handle;
  25.334 -
  25.335 -	/* Add a reference count to the type */
  25.336 -	m_Types[type].opened++;
  25.337 -
  25.338 -	/* Output */
  25.339 -	*in_pHandle = pHandle;
  25.340 -	*in_index = handle;
  25.341 -	*in_handle = hash;
  25.342 -
  25.343 -	/* Decode the identity token 
  25.344 -	 * For now, we don't allow nested ownership
  25.345 -	 */
  25.346 -	if (owner && !identity)
  25.347 -	{
  25.348 -		QHandle *pIdentity = &m_Handles[owner_index];
  25.349 -		if (pIdentity->ch_prev == 0)
  25.350 -		{
  25.351 -			pIdentity->ch_prev = handle;
  25.352 -			pIdentity->ch_next = handle;
  25.353 -			pHandle->ch_prev = 0;
  25.354 -		}
  25.355 -		else
  25.356 -		{
  25.357 -			/* Link previous node to us (forward) */
  25.358 -			m_Handles[pIdentity->ch_next].ch_next = handle;
  25.359 -			/* Link us to previous node (backwards) */
  25.360 -			pHandle->ch_prev = pIdentity->ch_next;
  25.361 -			/* Set new tail */
  25.362 -			pIdentity->ch_next = handle;
  25.363 -		}
  25.364 -		pIdentity->refcount++;
  25.365 -	}
  25.366 -	else
  25.367 -	{
  25.368 -		pHandle->ch_prev = 0;
  25.369 -	}
  25.370 -
  25.371 -	return HandleError_None;
  25.372 -}
  25.373 -
  25.374 -void HandleSystem::SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken)
  25.375 -{
  25.376 -	if (!type
  25.377 -		|| type >= HANDLESYS_TYPEARRAY_SIZE
  25.378 -		|| m_Types[type].dispatch == NULL)
  25.379 -	{
  25.380 -		return;
  25.381 -	}
  25.382 -
  25.383 -	m_Types[type].typeSec.ident = pToken;
  25.384 -}
  25.385 -
  25.386 -Handle_t HandleSystem::CreateHandleInt(HandleType_t type, 
  25.387 -									   void *object, 
  25.388 -									   const HandleSecurity *pSec,
  25.389 -									   HandleError *err, 
  25.390 -									   const HandleAccess *pAccess,
  25.391 -									   bool identity)
  25.392 -{
  25.393 -	IdentityToken_t *ident;
  25.394 -	IdentityToken_t *owner;
  25.395 -
  25.396 -	if (pSec)
  25.397 -	{
  25.398 -		ident = pSec->pIdentity;
  25.399 -		owner = pSec->pOwner;
  25.400 -	} else {
  25.401 -		ident = NULL;
  25.402 -		owner = NULL;
  25.403 -	}
  25.404 -
  25.405 -	if (!type 
  25.406 -		|| type >= HANDLESYS_TYPEARRAY_SIZE
  25.407 -		|| m_Types[type].dispatch == NULL)
  25.408 -	{
  25.409 -		if (err)
  25.410 -		{
  25.411 -			*err = HandleError_Parameter;
  25.412 -		}
  25.413 -		return 0;
  25.414 -	}
  25.415 -
  25.416 -	/* Check to see if we're allowed to create this handle type */
  25.417 -	QHandleType *pType = &m_Types[type];
  25.418 -	if (!pType->typeSec.access[HTypeAccess_Create]
  25.419 -	&& (!pType->typeSec.ident
  25.420 -		|| pType->typeSec.ident != ident))
  25.421 -	{
  25.422 -		if (err)
  25.423 -		{
  25.424 -			*err = HandleError_Access;
  25.425 -		}
  25.426 -		return 0;
  25.427 -	}
  25.428 -
  25.429 -	unsigned int index;
  25.430 -	Handle_t handle;
  25.431 -	QHandle *pHandle;
  25.432 -	HandleError _err;
  25.433 -
  25.434 -	if ((_err=MakePrimHandle(type, &pHandle, &index, &handle, owner, identity)) != HandleError_None)
  25.435 -	{
  25.436 -		if (err)
  25.437 -		{
  25.438 -			*err = _err;
  25.439 -		}
  25.440 -		return 0;
  25.441 -	}
  25.442 -
  25.443 -	if (pAccess)
  25.444 -	{
  25.445 -		pHandle->access_special = true;
  25.446 -		pHandle->sec = *pAccess;
  25.447 -	}
  25.448 -
  25.449 -	pHandle->object = object;
  25.450 -	pHandle->clone = 0;
  25.451 -
  25.452 -	return handle;
  25.453 -}
  25.454 -
  25.455 -Handle_t HandleSystem::CreateHandleEx(HandleType_t type, void *object, const HandleSecurity *pSec, const HandleAccess *pAccess, HandleError *err)
  25.456 -{
  25.457 -	return CreateHandleInt(type, object, pSec, err, pAccess, false);
  25.458 -}
  25.459 -
  25.460 -Handle_t HandleSystem::CreateHandle(HandleType_t type, void *object, IdentityToken_t *owner, IdentityToken_t *ident, HandleError *err)
  25.461 -{
  25.462 -	HandleSecurity sec;
  25.463 -
  25.464 -	sec.pIdentity = ident;
  25.465 -	sec.pOwner = owner;
  25.466 -
  25.467 -	return CreateHandleEx(type, object, &sec, NULL, err);
  25.468 -}
  25.469 -
  25.470 -bool HandleSystem::TypeCheck(HandleType_t intype, HandleType_t outtype)
  25.471 -{
  25.472 -	/* Check the type inheritance */
  25.473 -	if (intype & HANDLESYS_SUBTYPE_MASK)
  25.474 -	{
  25.475 -		if (intype != outtype
  25.476 -			&& (TypeParent(intype) != TypeParent(outtype)))
  25.477 -		{
  25.478 -			return false;
  25.479 -		}
  25.480 -	} else {
  25.481 -		if (intype != outtype)
  25.482 -		{
  25.483 -			return false;
  25.484 -		}
  25.485 -	}
  25.486 -
  25.487 -	return true;
  25.488 -}
  25.489 -
  25.490 -HandleError HandleSystem::GetHandle(Handle_t handle,
  25.491 -									IdentityToken_t *ident, 
  25.492 -									QHandle **in_pHandle, 
  25.493 -									unsigned int *in_index,
  25.494 -									bool ignoreFree)
  25.495 -{
  25.496 -	unsigned int serial = (handle >> 16);
  25.497 -	unsigned int index = (handle & HANDLESYS_HANDLE_MASK);
  25.498 -
  25.499 -	if (index == 0 || index > m_HandleTail || index > HANDLESYS_MAX_HANDLES)
  25.500 -	{
  25.501 -		return HandleError_Index;
  25.502 -	}
  25.503 -
  25.504 -	QHandle *pHandle = &m_Handles[index];
  25.505 -
  25.506 -	if (!pHandle->set
  25.507 -		|| (pHandle->set == HandleSet_Freed && !ignoreFree))
  25.508 -	{
  25.509 -		return HandleError_Freed;
  25.510 -	} else if (pHandle->set == HandleSet_Identity
  25.511 -			   && ident != g_ShareSys.GetIdentRoot())
  25.512 -	{
  25.513 -		/* Only IdentityHandle() can read this! */
  25.514 -		return HandleError_Identity;
  25.515 -	}
  25.516 -	if (pHandle->serial != serial)
  25.517 -	{
  25.518 -		return HandleError_Changed;
  25.519 -	}
  25.520 -
  25.521 -	*in_pHandle = pHandle;
  25.522 -	*in_index = index;
  25.523 -
  25.524 -	return HandleError_None;
  25.525 -}
  25.526 -
  25.527 -bool HandleSystem::CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity)
  25.528 -{
  25.529 -	QHandleType *pType = &m_Types[pHandle->type];
  25.530 -	unsigned int access;
  25.531 -
  25.532 -	if (pHandle->access_special)
  25.533 -	{
  25.534 -		access = pHandle->sec.access[right];
  25.535 -	} else {
  25.536 -		access = pType->hndlSec.access[right];
  25.537 -	}
  25.538 -
  25.539 -	/* Check if the type's identity matches */
  25.540 -	if (access & HANDLE_RESTRICT_IDENTITY)
  25.541 -	{
  25.542 -		IdentityToken_t *owner = pType->typeSec.ident;
  25.543 -		if (!owner
  25.544 -			|| (!pSecurity || pSecurity->pIdentity != owner))
  25.545 -		{
  25.546 -			return false;
  25.547 -		}
  25.548 -	}
  25.549 -
  25.550 -	/* Check if the owner is allowed */
  25.551 -	if (access & HANDLE_RESTRICT_OWNER)
  25.552 -	{
  25.553 -		IdentityToken_t *owner = pHandle->owner;
  25.554 -		if (owner
  25.555 -			&& (!pSecurity || pSecurity->pOwner != owner))
  25.556 -		{
  25.557 -			return false;
  25.558 -		}
  25.559 -	}
  25.560 -
  25.561 -	return true;
  25.562 -}
  25.563 -
  25.564 -HandleError HandleSystem::CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner)
  25.565 -{
  25.566 -	/* Get a new Handle ID */
  25.567 -	unsigned int new_index;
  25.568 -	QHandle *pNewHandle;
  25.569 -	Handle_t new_handle;
  25.570 -	HandleError err;
  25.571 -
  25.572 -	if ((err=MakePrimHandle(pHandle->type, &pNewHandle, &new_index, &new_handle, newOwner)) != HandleError_None)
  25.573 -	{
  25.574 -		return err;
  25.575 -	}
  25.576 -
  25.577 -	/* Assign permissions from parent */
  25.578 -	if (pHandle->access_special)
  25.579 -	{
  25.580 -		pNewHandle->access_special = true;
  25.581 -		pNewHandle->sec = pHandle->sec;
  25.582 -	}
  25.583 -
  25.584 -	pNewHandle->clone = index;
  25.585 -	pHandle->refcount++;
  25.586 -
  25.587 -	*newhandle = new_handle;
  25.588 -
  25.589 -	return HandleError_None;
  25.590 -}
  25.591 -
  25.592 -HandleError HandleSystem::CloneHandle(Handle_t handle, Handle_t *newhandle, IdentityToken_t *newOwner, const HandleSecurity *pSecurity)
  25.593 -{
  25.594 -	HandleError err;
  25.595 -	QHandle *pHandle;
  25.596 -	unsigned int index;
  25.597 -	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
  25.598 -
  25.599 -	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
  25.600 -	{
  25.601 -		return err;
  25.602 -	}
  25.603 -
  25.604 -	/* Identities cannot be cloned */
  25.605 -	if (pHandle->set == HandleSet_Identity)
  25.606 -	{
  25.607 -		return HandleError_Identity;
  25.608 -	}
  25.609 -
  25.610 -	/* Check if the handle can be cloned */
  25.611 -	if (!CheckAccess(pHandle, HandleAccess_Clone, pSecurity))
  25.612 -	{
  25.613 -		return HandleError_Access;
  25.614 -	}
  25.615 -
  25.616 -	/* Make sure we're not cloning a clone */
  25.617 -	if (pHandle->clone)
  25.618 -	{
  25.619 -		QHandle *pParent = &m_Handles[pHandle->clone];
  25.620 -		return CloneHandle(pParent, pHandle->clone, newhandle, newOwner);
  25.621 -	}
  25.622 -
  25.623 -	return CloneHandle(pHandle, index, newhandle, newOwner);
  25.624 -}
  25.625 -
  25.626 -HandleError HandleSystem::FreeHandle(QHandle *pHandle, unsigned int index)
  25.627 -{
  25.628 -	QHandleType *pType = &m_Types[pHandle->type];
  25.629 -
  25.630 -	if (pHandle->clone)
  25.631 -	{
  25.632 -		/* If we're a clone, decrease the parent reference count */
  25.633 -		QHandle *pMaster;
  25.634 -		unsigned int master;
  25.635 -
  25.636 -		/* Note that if we ever have per-handle security, we would need to re-check
  25.637 -		* the access on this Handle. */
  25.638 -		master = pHandle->clone;
  25.639 -		pMaster = &m_Handles[master];
  25.640 -
  25.641 -		/* Release the clone now */
  25.642 -		ReleasePrimHandle(index);
  25.643 -
  25.644 -		/* Decrement the master's reference count */
  25.645 -		if (--pMaster->refcount == 0)
  25.646 -		{
  25.647 -			/* Type should be the same but do this anyway... */
  25.648 -			pType = &m_Types[pMaster->type];
  25.649 -			pMaster->is_destroying = true;
  25.650 -			pType->dispatch->OnHandleDestroy(pMaster->type, pMaster->object);
  25.651 -			ReleasePrimHandle(master);
  25.652 -		}
  25.653 -	} else if (pHandle->set == HandleSet_Identity) {
  25.654 -		/* If we're an identity, skip all this stuff!
  25.655 -		 * NOTE: SHARESYS DOES NOT CARE ABOUT THE DESTRUCTOR
  25.656 -		 */
  25.657 -		ReleasePrimHandle(index);
  25.658 -	} else {
  25.659 -		/* Decrement, free if necessary */
  25.660 -		if (--pHandle->refcount == 0)
  25.661 -		{
  25.662 -			pHandle->is_destroying = true;
  25.663 -			pType->dispatch->OnHandleDestroy(pHandle->type, pHandle->object);
  25.664 -			ReleasePrimHandle(index);
  25.665 -		} else {
  25.666 -			/* We must be cloned, so mark ourselves as freed */
  25.667 -			pHandle->set = HandleSet_Freed;
  25.668 -			/* Now, unlink us, so we're not being tracked by the owner */
  25.669 -			if (pHandle->owner)
  25.670 -			{
  25.671 -				UnlinkHandleFromOwner(pHandle, index);
  25.672 -			}
  25.673 -		}
  25.674 -	}
  25.675 -
  25.676 -	return HandleError_None;
  25.677 -}
  25.678 -
  25.679 -HandleError HandleSystem::FreeHandle(Handle_t handle, const HandleSecurity *pSecurity)
  25.680 -{
  25.681 -	unsigned int index;
  25.682 -	QHandle *pHandle;
  25.683 -	HandleError err;
  25.684 -	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
  25.685 -
  25.686 -	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
  25.687 -	{
  25.688 -		return err;
  25.689 -	}
  25.690 -
  25.691 -	if (!CheckAccess(pHandle, HandleAccess_Delete, pSecurity))
  25.692 -	{
  25.693 -		return HandleError_Access;
  25.694 -	}
  25.695 -
  25.696 -	if (pHandle->is_destroying)
  25.697 -	{
  25.698 -		/* Someone tried to free this recursively.  
  25.699 -		 * We'll just ignore this safely.
  25.700 -		 */
  25.701 -		return HandleError_None;
  25.702 -	}
  25.703 -
  25.704 -	return FreeHandle(pHandle, index);
  25.705 -}
  25.706 -
  25.707 -HandleError HandleSystem::ReadHandle(Handle_t handle, HandleType_t type, const HandleSecurity *pSecurity, void **object)
  25.708 -{
  25.709 -	unsigned int index;
  25.710 -	QHandle *pHandle;
  25.711 -	HandleError err;
  25.712 -	IdentityToken_t *ident = pSecurity ? pSecurity->pIdentity : NULL;
  25.713 -
  25.714 -	if ((err=GetHandle(handle, ident, &pHandle, &index)) != HandleError_None)
  25.715 -	{
  25.716 -		return err;
  25.717 -	}
  25.718 -
  25.719 -	if (!CheckAccess(pHandle, HandleAccess_Read, pSecurity))
  25.720 -	{
  25.721 -		return HandleError_Access;
  25.722 -	}
  25.723 -
  25.724 -	/* Check the type inheritance */
  25.725 -	if (pHandle->type & HANDLESYS_SUBTYPE_MASK)
  25.726 -	{
  25.727 -		if (pHandle->type != type
  25.728 -			&& (TypeParent(pHandle->type) != TypeParent(type)))
  25.729 -		{
  25.730 -			return HandleError_Type;
  25.731 -		}
  25.732 -	} else if (type) {
  25.733 -		if (pHandle->type != type)
  25.734 -		{
  25.735 -			return HandleError_Type;
  25.736 -		}
  25.737 -	}
  25.738 -
  25.739 -	if (object)
  25.740 -	{
  25.741 -		/* if we're a clone, the rules change - object is ONLY in our reference */
  25.742 -		if (pHandle->clone)
  25.743 -		{
  25.744 -			pHandle = &m_Handles[pHandle->clone];
  25.745 -		}
  25.746 -		*object = pHandle->object;
  25.747 -	}
  25.748 -
  25.749 -	return HandleError_None;
  25.750 -}
  25.751 -
  25.752 -void HandleSystem::UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index)
  25.753 -{
  25.754 -	/* Unlink us if necessary */
  25.755 -	unsigned int ident_index;
  25.756 -	if (IdentityHandle(pHandle->owner, &ident_index) != HandleError_None)
  25.757 -	{
  25.758 -		/* Uh-oh! */
  25.759 -		assert(pHandle->owner == 0);
  25.760 -		return;
  25.761 -	}
  25.762 -	/* Note that since 0 is an invalid handle, if any of these links are 0,
  25.763 -	* the data can still be set.
  25.764 -	*/
  25.765 -	QHandle *pIdentity = &m_Handles[ident_index];
  25.766 -
  25.767 -	/* Unlink case: We're the head AND tail node */
  25.768 -	if (index == pIdentity->ch_prev && index == pIdentity->ch_next)
  25.769 -	{
  25.770 -		pIdentity->ch_prev = 0;
  25.771 -		pIdentity->ch_next = 0;
  25.772 -	}
  25.773 -	/* Unlink case: We're the head node */
  25.774 -	else if (index == pIdentity->ch_prev) {
  25.775 -		/* Link us to the next in the chain */
  25.776 -		pIdentity->ch_prev = pHandle->ch_next;
  25.777 -		/* Patch up the previous link */
  25.778 -		m_Handles[pHandle->ch_next].ch_prev = 0;
  25.779 -	}
  25.780 -	/* Unlink case: We're the tail node */
  25.781 -	else if (index == pIdentity->ch_next) {
  25.782 -		/* Link us to the previous in the chain */
  25.783 -		pIdentity->ch_next = pHandle->ch_prev;
  25.784 -		/* Patch up the next link */
  25.785 -		m_Handles[pHandle->ch_prev].ch_next = 0;
  25.786 -	}
  25.787 -	/* Unlink case: We're in the middle! */
  25.788 -	else {
  25.789 -		/* Patch the forward reference */
  25.790 -		m_Handles[pHandle->ch_next].ch_prev = pHandle->ch_prev;
  25.791 -		/* Patch the backward reference */
  25.792 -		m_Handles[pHandle->ch_prev].ch_next = pHandle->ch_next;
  25.793 -	}
  25.794 -
  25.795 -	/* Lastly, decrease the reference count */
  25.796 -	pIdentity->refcount--;
  25.797 -}
  25.798 -
  25.799 -void HandleSystem::ReleasePrimHandle(unsigned int index)
  25.800 -{
  25.801 -	QHandle *pHandle = &m_Handles[index];
  25.802 -	HandleSet set = pHandle->set;
  25.803 -
  25.804 -	if (pHandle->owner && (set != HandleSet_Identity))
  25.805 -	{
  25.806 -		UnlinkHandleFromOwner(pHandle, index);
  25.807 -	}
  25.808 -
  25.809 -	/* Were we an identity ourself? */
  25.810 -	QHandle *pLocal;
  25.811 -	if (set == HandleSet_Identity)
  25.812 -	{
  25.813 -		/* Extra work to do.  We need to find everything connected to this identity and release it. */
  25.814 -		unsigned int ch_index;
  25.815 -#if defined _DEBUG
  25.816 -		unsigned int old_index = 0;
  25.817 -#endif
  25.818 -		while ((ch_index = pHandle->ch_next) != 0)
  25.819 -		{
  25.820 -			pLocal = &m_Handles[ch_index];
  25.821 -#if defined _DEBUG
  25.822 -			assert(old_index != ch_index);
  25.823 -			assert(pLocal->set == HandleSet_Used);
  25.824 -			old_index = ch_index;
  25.825 -#endif
  25.826 -			FreeHandle(pLocal, ch_index);
  25.827 -		}
  25.828 -	}
  25.829 -
  25.830 -	pHandle->set = HandleSet_None;
  25.831 -	m_Types[pHandle->type].opened--;
  25.832 -	m_Handles[++m_FreeHandles].freeID = index;
  25.833 -}
  25.834 -
  25.835 -bool HandleSystem::RemoveType(HandleType_t type, IdentityToken_t *ident)
  25.836 -{
  25.837 -	if (type == 0 || type >= HANDLESYS_TYPEARRAY_SIZE)
  25.838 -	{
  25.839 -		return false;
  25.840 -	}
  25.841 -
  25.842 -	QHandleType *pType = &m_Types[type];
  25.843 -
  25.844 -	if (pType->typeSec.ident
  25.845 -		&& pType->typeSec.ident != ident)
  25.846 -	{
  25.847 -		return false;
  25.848 -	}
  25.849 -
  25.850 -	if (pType->dispatch == NULL)
  25.851 -	{
  25.852 -		return false;
  25.853 -	}
  25.854 -
  25.855 -	/* Remove children if we have to */
  25.856 -	if (!(type & HANDLESYS_SUBTYPE_MASK))
  25.857 -	{
  25.858 -		QHandleType *childType;
  25.859 -		for (unsigned int i=1; i<=HANDLESYS_MAX_SUBTYPES; i++)
  25.860 -		{
  25.861 -			childType = &m_Types[type + i];
  25.862 -			if (childType->dispatch)
  25.863 -			{
  25.864 -				RemoveType(type + i, childType->typeSec.ident);
  25.865 -			}
  25.866 -		}
  25.867 -		/* Link us into the free chain */
  25.868 -		m_Types[++m_FreeTypes].freeID = type;
  25.869 -	}
  25.870 -
  25.871 -	/* Invalidate the type now */
  25.872 -	IHandleTypeDispatch *dispatch = pType->dispatch;
  25.873 -	pType->dispatch = NULL;
  25.874 -
  25.875 -	/* Make sure nothing is using this type. */
  25.876 -	if (pType->opened)
  25.877 -	{
  25.878 -		QHandle *pHandle;
  25.879 -		for (unsigned int i=1; i<=m_HandleTail; i++)
  25.880 -		{
  25.881 -			pHandle = &m_Handles[i];
  25.882 -			if (!pHandle->set || pHandle->type != type)
  25.883 -			{
  25.884 -				continue;
  25.885 -			}
  25.886 -			if (pHandle->clone)
  25.887 -			{
  25.888 -				/* Get parent */
  25.889 -				QHandle *pOther = &m_Handles[pHandle->clone];
  25.890 -				if (--pOther->refcount == 0)
  25.891 -				{
  25.892 -					/* Free! */
  25.893 -					dispatch->OnHandleDestroy(type, pOther->object);
  25.894 -					ReleasePrimHandle(pHandle->clone);
  25.895 -				}
  25.896 -				/* Unlink ourselves since we don't have a reference count */
  25.897 -				ReleasePrimHandle(i);
  25.898 -			} else {
  25.899 -				/* If it's not a clone, we still have to check the reference count.
  25.900 -				 * Either way, we'll be destroyed eventually because the handle types do not change.
  25.901 -				 */
  25.902 -				if (--pHandle->refcount == 0)
  25.903 -				{
  25.904 -					/* Free! */
  25.905 -					dispatch->OnHandleDestroy(type, pHandle->object);
  25.906 -					ReleasePrimHandle(i);
  25.907 -				}
  25.908 -			}
  25.909 -			if (pType->opened == 0)
  25.910 -			{
  25.911 -				break;
  25.912 -			}
  25.913 -		}
  25.914 -	}
  25.915 -
  25.916 -	/* Remove it from the type cache. */
  25.917 -	if (pType->nameIdx != -1)
  25.918 -	{
  25.919 -		const char *typeName;
  25.920 -
  25.921 -		typeName = m_strtab->GetString(pType->nameIdx);
  25.922 -		sm_trie_delete(m_TypeLookup, typeName);
  25.923 -	}
  25.924 -
  25.925 -	return true;
  25.926 -}
  25.927 -
  25.928 -bool HandleSystem::InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess)
  25.929 -{
  25.930 -	if (pTypeAccess)
  25.931 -	{
  25.932 -		if (pTypeAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
  25.933 -		{
  25.934 -			return false;
  25.935 -		}
  25.936 -		pTypeAccess->access[HTypeAccess_Create] = false;
  25.937 -		pTypeAccess->access[HTypeAccess_Inherit] = false;
  25.938 -		pTypeAccess->ident = NULL;
  25.939 -	}
  25.940 -
  25.941 -	if (pHandleAccess)
  25.942 -	{
  25.943 -		if (pHandleAccess->hsVersion > SMINTERFACE_HANDLESYSTEM_VERSION)
  25.944 -		{
  25.945 -			return false;
  25.946 -		}
  25.947 -
  25.948 -		pHandleAccess->access[HandleAccess_Clone] = 0;
  25.949 -		pHandleAccess->access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER;
  25.950 -		pHandleAccess->access[HandleAccess_Read] = HANDLE_RESTRICT_IDENTITY;
  25.951 -	}
  25.952 -
  25.953 -	return true;
  25.954 -}
  25.955 -
  25.956 -bool HandleSystem::TryAndFreeSomeHandles()
  25.957 -{
  25.958 -	IPluginIterator *pl_iter = g_PluginSys.GetPluginIterator();
  25.959 -	IPlugin *highest_owner = NULL;
  25.960 -	unsigned int highest_handle_count = 0;
  25.961 -
  25.962 -	/* Search all plugins */
  25.963 -	while (pl_iter->MorePlugins())
  25.964 -	{
  25.965 -		IPlugin *plugin = pl_iter->GetPlugin();
  25.966 -		IdentityToken_t *identity = plugin->GetIdentity();
  25.967 -		unsigned int handle_count = 0;
  25.968 -
  25.969 -		if (identity == NULL)
  25.970 -		{
  25.971 -			continue;
  25.972 -		}
  25.973 -
  25.974 -		/* Search all handles */
  25.975 -		for (unsigned int i = 1; i <= m_HandleTail; i++)
  25.976 -		{
  25.977 -			if (m_Handles[i].set != HandleSet_Used)
  25.978 -			{
  25.979 -				continue;
  25.980 -			}
  25.981 -			if (m_Handles[i].owner == identity)
  25.982 -			{
  25.983 -				handle_count++;
  25.984 -			}
  25.985 -		}
  25.986 -
  25.987 -		if (handle_count > highest_handle_count)
  25.988 -		{
  25.989 -			highest_owner = plugin;
  25.990 -			highest_handle_count = handle_count;
  25.991 -		}
  25.992 -
  25.993 -		pl_iter->NextPlugin();
  25.994 -	}
  25.995 -
  25.996 -	if (highest_owner == NULL || highest_handle_count == 0)
  25.997 -	{
  25.998 -		return false;
  25.999 -	}
 25.1000 -
 25.1001 -	g_Logger.LogFatal("[SM] MEMORY LEAK DETECTED IN PLUGIN (file \"%s\")", highest_owner->GetFilename());
 25.1002 -	g_Logger.LogFatal("[SM] Reloading plugin to free %d handles.", highest_handle_count);
 25.1003 -	g_Logger.LogFatal("[SM] Contact the author(s) of this plugin to correct this error.", highest_handle_count);
 25.1004 -
 25.1005 -	highest_owner->GetBaseContext()->ThrowNativeErrorEx(SP_ERROR_MEMACCESS, "Memory leak");
 25.1006 -
 25.1007 -	return g_PluginSys.UnloadPlugin(highest_owner);
 25.1008 -}
 25.1009 -
 25.1010 -void HandleSystem::Dump(HANDLE_REPORTER rep)
 25.1011 -{
 25.1012 -	unsigned int total_size = 0;
 25.1013 -	rep("%-10.10s\t%-20.20s\t%-20.20s\t%-10.10s", "Handle", "Owner", "Type", "Memory");
 25.1014 -	rep("--------------------------------------------------------------------------");
 25.1015 -	for (unsigned int i = 1; i <= m_HandleTail; i++)
 25.1016 -	{
 25.1017 -		if (m_Handles[i].set != HandleSet_Used)
 25.1018 -		{
 25.1019 -			continue;
 25.1020 -		}
 25.1021 -		/* Get the index */
 25.1022 -		unsigned int index = (m_Handles[i].serial << 16) | i;
 25.1023 -		/* Determine the owner */
 25.1024 -		const char *owner = "UNKNOWN";
 25.1025 -		if (m_Handles[i].owner)
 25.1026 -		{
 25.1027 -			IdentityToken_t *pOwner = m_Handles[i].owner;
 25.1028 -			if (pOwner == g_pCoreIdent)
 25.1029 -			{
 25.1030 -				owner = "CORE";
 25.1031 -			}
 25.1032 -			else if (pOwner == g_PluginSys.GetIdentity())
 25.1033 -			{
 25.1034 -				owner = "PLUGINSYS";
 25.1035 -			}
 25.1036 -			else
 25.1037 -			{
 25.1038 -				CExtension *ext = g_Extensions.GetExtensionFromIdent(pOwner);
 25.1039 -				if (ext)
 25.1040 -				{
 25.1041 -					owner = ext->GetFilename();
 25.1042 -				}
 25.1043 -				else
 25.1044 -				{
 25.1045 -					CPlugin *pPlugin = g_PluginSys.GetPluginFromIdentity(pOwner);
 25.1046 -					if (pPlugin)
 25.1047 -					{
 25.1048 -						owner = pPlugin->GetFilename();
 25.1049 -					}
 25.1050 -				}
 25.1051 -			}
 25.1052 -		}
 25.1053 -		else
 25.1054 -		{
 25.1055 -			owner = "NONE";
 25.1056 -		}
 25.1057 -		const char *type = "ANON";
 25.1058 -		QHandleType *pType = &m_Types[m_Handles[i].type];
 25.1059 -		unsigned int size = 0;
 25.1060 -		if (pType->nameIdx != -1)
 25.1061 -		{
 25.1062 -			type = m_strtab->GetString(pType->nameIdx);
 25.1063 -		}
 25.1064 -		if (pType->dispatch->GetDispatchVersion() < HANDLESYS_MEMUSAGE_MIN_VERSION
 25.1065 -			|| !pType->dispatch->GetHandleApproxSize(m_Handles[i].type, m_Handles[i].object, &size))
 25.1066 -		{
 25.1067 -			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, "-1");
 25.1068 -		}
 25.1069 -		else
 25.1070 -		{
 25.1071 -			char buffer[32];
 25.1072 -			UTIL_Format(buffer, sizeof(buffer), "%d", size);
 25.1073 -			rep("0x%08x\t%-20.20s\t%-20.20s\t%-10.10s", index, owner, type, buffer);
 25.1074 -			total_size += size;
 25.1075 -		}
 25.1076 -	}
 25.1077 -	rep("-- Approximately %d bytes of memory are in use by Handles.\n", total_size);
 25.1078 -}
 25.1079 -
    26.1 --- a/core/systems/HandleSys.h	Mon Nov 24 08:25:36 2008 -0600
    26.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.3 @@ -1,225 +0,0 @@
    26.4 -/**
    26.5 - * vim: set ts=4 :
    26.6 - * =============================================================================
    26.7 - * SourceMod
    26.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    26.9 - * =============================================================================
   26.10 - *
   26.11 - * This program is free software; you can redistribute it and/or modify it under
   26.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   26.13 - * Free Software Foundation.
   26.14 - * 
   26.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   26.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   26.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   26.18 - * details.
   26.19 - *
   26.20 - * You should have received a copy of the GNU General Public License along with
   26.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   26.22 - *
   26.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   26.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   26.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   26.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   26.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   26.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   26.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   26.30 - * or <http://www.sourcemod.net/license.php>.
   26.31 - *
   26.32 - * Version: $Id$
   26.33 - */
   26.34 -
   26.35 -#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
   26.36 -#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
   26.37 -
   26.38 -#include <IHandleSys.h>
   26.39 -#include <stdio.h>
   26.40 -#include "sm_globals.h"
   26.41 -#include "sm_trie.h"
   26.42 -#include "sourcemod.h"
   26.43 -#include "sm_memtable.h"
   26.44 -
   26.45 -#define HANDLESYS_MAX_HANDLES		(1<<14)
   26.46 -#define HANDLESYS_MAX_TYPES			(1<<9)
   26.47 -#define HANDLESYS_MAX_SUBTYPES		0xF
   26.48 -#define HANDLESYS_SUBTYPE_MASK		0xF
   26.49 -#define HANDLESYS_TYPEARRAY_SIZE	(HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
   26.50 -#define HANDLESYS_MAX_SERIALS		0xFFFF
   26.51 -#define HANDLESYS_SERIAL_MASK		0xFFFF0000
   26.52 -#define HANDLESYS_HANDLE_MASK		0x0000FFFF
   26.53 -
   26.54 -#define HANDLESYS_MEMUSAGE_MIN_VERSION		3
   26.55 -
   26.56 -/**
   26.57 - *   The QHandle is a nasty structure that compacts the handle system into a big vector.
   26.58 - * The members of the vector each encapsulate one Handle, however, they also act as nodes
   26.59 - * in an inlined linked list and an inlined vector.
   26.60 - *
   26.61 - *   The first of these lists is the 'freeID' list.  Each node from 1 to N (where N
   26.62 - * is the number of free nodes) has a 'freeID' that specifies a free Handle ID.  This
   26.63 - * is a quick hack to get around allocating a second base vector.
   26.64 - *
   26.65 - *   The second vector is the identity linked list.  An identity has its own handle, so
   26.66 - * these handles are used as sentinel nodes for index linking.  They point to the first and last
   26.67 - * index into the handle array.  Each subsequent Handle who is owned by that identity is mapped into
   26.68 - * that list.  This lets owning identities be unloaded in O(n) time.
   26.69 - *
   26.70 - *   Eventually, there may be a third list for type chains.
   26.71 - */
   26.72 -
   26.73 -enum HandleSet
   26.74 -{
   26.75 -	HandleSet_None = 0,
   26.76 -	HandleSet_Used,			/* The Handle is in use */
   26.77 -	HandleSet_Freed,		/* The "master" Handle of a clone chain is freed */
   26.78 -	HandleSet_Identity,		/* The Handle is a special identity */
   26.79 -};
   26.80 -
   26.81 -struct QHandle
   26.82 -{
   26.83 -	HandleType_t type;			/* Handle type */
   26.84 -	void *object;				/* Unmaintained object pointer */
   26.85 -	IdentityToken_t *owner;		/* Identity of object which owns this */
   26.86 -	unsigned int serial;		/* Serial no. for sanity checking */
   26.87 -	unsigned int refcount;		/* Reference count for safe destruction */
   26.88 -	unsigned int clone;			/* If non-zero, this is our cloned parent index */
   26.89 -	HandleSet set;				/* Information about the handle's state */
   26.90 -	bool access_special;		/* Whether or not access rules are special or type-derived */
   26.91 -	bool is_destroying;			/* Whether or not the handle is being destroyed */
   26.92 -	HandleAccess sec;			/* Security rules */
   26.93 -	/* The following variables are unrelated to the Handle array, and used 
   26.94 -	 * as an inlined chain of information */
   26.95 -	unsigned int freeID;		/* ID of a free handle in the free handle chain */
   26.96 -	/* Indexes into the handle array for owner membership.
   26.97 -	 * For identity roots, these are treated as the head/tail. */
   26.98 -	unsigned int ch_prev;		/* chained previous handle */
   26.99 -	unsigned int ch_next;		/* chained next handle */
  26.100 -};
  26.101 -
  26.102 -struct QHandleType
  26.103 -{
  26.104 -	IHandleTypeDispatch *dispatch;
  26.105 -	unsigned int freeID;
  26.106 -	unsigned int children;
  26.107 -	TypeAccess typeSec;
  26.108 -	HandleAccess hndlSec;
  26.109 -	unsigned int opened;
  26.110 -	int nameIdx;
  26.111 -};
  26.112 -
  26.113 -typedef void (HANDLE_REPORTER)(const char *str, ...);
  26.114 -
  26.115 -class HandleSystem : 
  26.116 -	public IHandleSys
  26.117 -{
  26.118 -	friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
  26.119 -	friend class ShareSystem;
  26.120 -public:
  26.121 -	HandleSystem();
  26.122 -	~HandleSystem();
  26.123 -public: //IHandleSystem
  26.124 -
  26.125 -	HandleType_t CreateType(const char *name,
  26.126 -		IHandleTypeDispatch *dispatch,
  26.127 -		HandleType_t parent,
  26.128 -		const TypeAccess *typeAccess,
  26.129 -		const HandleAccess *hndlAccess,
  26.130 -		IdentityToken_t *ident,
  26.131 -		HandleError *err);
  26.132 -
  26.133 -	bool RemoveType(HandleType_t type, IdentityToken_t *ident);
  26.134 -
  26.135 -	bool FindHandleType(const char *name, HandleType_t *type);
  26.136 -
  26.137 -	Handle_t CreateHandle(HandleType_t type, 
  26.138 -		void *object,
  26.139 -		IdentityToken_t *owner,
  26.140 -		IdentityToken_t *ident,
  26.141 -		HandleError *err);
  26.142 -
  26.143 -	HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
  26.144 -
  26.145 -	HandleError CloneHandle(Handle_t handle, 
  26.146 -		Handle_t *newhandle, 
  26.147 -		IdentityToken_t *newOwner,
  26.148 -		const HandleSecurity *pSecurity);
  26.149 -
  26.150 -	HandleError ReadHandle(Handle_t handle, 
  26.151 -		HandleType_t type, 
  26.152 -		const HandleSecurity *pSecurity,
  26.153 -		void **object);
  26.154 -
  26.155 -	bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
  26.156 -
  26.157 -	bool TypeCheck(HandleType_t intype, HandleType_t outtype);
  26.158 -
  26.159 -	virtual Handle_t CreateHandleEx(HandleType_t type, 
  26.160 -		void *object,
  26.161 -		const HandleSecurity *pSec,
  26.162 -		const HandleAccess *pAccess,
  26.163 -		HandleError *err);
  26.164 -
  26.165 -	void Dump(HANDLE_REPORTER rep);
  26.166 -protected:
  26.167 -	/**
  26.168 -	 * Decodes a handle with sanity and security checking.
  26.169 -	 */
  26.170 -	HandleError GetHandle(Handle_t handle, 
  26.171 -						  IdentityToken_t *ident, 
  26.172 -						  QHandle **pHandle, 
  26.173 -						  unsigned int *index,
  26.174 -						  bool ignoreFree=false);
  26.175 -
  26.176 -	/**
  26.177 -	 * Creates a basic handle and sets its reference count to 1.
  26.178 -	 * Does not do any type or security checking.
  26.179 -	 */
  26.180 -	HandleError MakePrimHandle(HandleType_t type, 
  26.181 -							   QHandle **pHandle, 
  26.182 -							   unsigned int *index, 
  26.183 -							   HandleType_t *handle,
  26.184 -							   IdentityToken_t *owner,
  26.185 -							   bool identity=false);
  26.186 -
  26.187 -	/**
  26.188 -	 * Frees a primitive handle.  Does no object freeing, only reference count, bookkeeping, 
  26.189 -	 * and linked list maintenance.
  26.190 -	 * If used on an Identity handle, destroys all Handles under that identity.
  26.191 -	 */
  26.192 -	void ReleasePrimHandle(unsigned int index);
  26.193 -
  26.194 -	/**
  26.195 -	 * Sets the security owner of a type.
  26.196 -	 */
  26.197 -	void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
  26.198 -
  26.199 -	/**
  26.200 -	 * Helper function to check access rights.
  26.201 -	 */
  26.202 -	bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
  26.203 -
  26.204 -	/** 
  26.205 -	 * Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
  26.206 -	 */
  26.207 -	HandleError FreeHandle(QHandle *pHandle, unsigned int index);
  26.208 -	void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
  26.209 -	HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
  26.210 -	Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
  26.211 -
  26.212 -	bool TryAndFreeSomeHandles();
  26.213 -	HandleError TryAllocHandle(unsigned int *handle);
  26.214 -private:
  26.215 -	QHandle *m_Handles;
  26.216 -	QHandleType *m_Types;
  26.217 -	Trie *m_TypeLookup;
  26.218 -	unsigned int m_TypeTail;
  26.219 -	unsigned int m_FreeTypes;
  26.220 -	unsigned int m_HandleTail;
  26.221 -	unsigned int m_FreeHandles;
  26.222 -	unsigned int m_HSerial;
  26.223 -	BaseStringTable *m_strtab;
  26.224 -};
  26.225 -
  26.226 -extern HandleSystem g_HandleSys;
  26.227 -
  26.228 -#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
    27.1 --- a/core/systems/LibrarySys.cpp	Mon Nov 24 08:25:36 2008 -0600
    27.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.3 @@ -1,441 +0,0 @@
    27.4 -/**
    27.5 - * vim: set ts=4 :
    27.6 - * =============================================================================
    27.7 - * SourceMod
    27.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    27.9 - * =============================================================================
   27.10 - *
   27.11 - * This program is free software; you can redistribute it and/or modify it under
   27.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   27.13 - * Free Software Foundation.
   27.14 - * 
   27.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   27.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   27.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   27.18 - * details.
   27.19 - *
   27.20 - * You should have received a copy of the GNU General Public License along with
   27.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   27.22 - *
   27.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   27.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   27.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   27.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   27.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   27.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   27.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   27.30 - * or <http://www.sourcemod.net/license.php>.
   27.31 - *
   27.32 - * Version: $Id$
   27.33 - */
   27.34 -
   27.35 -#include <sys/stat.h>
   27.36 -#include <stdio.h>
   27.37 -#include <stdarg.h>
   27.38 -#include <string.h>
   27.39 -#include <sm_platform.h>
   27.40 -#include "sm_stringutil.h"
   27.41 -#include "LibrarySys.h"
   27.42 -
   27.43 -LibrarySystem g_LibSys;
   27.44 -
   27.45 -CLibrary::~CLibrary()
   27.46 -{
   27.47 -	if (m_lib)
   27.48 -	{
   27.49 -#if defined PLATFORM_WINDOWS
   27.50 -		FreeLibrary(m_lib);
   27.51 -#elif defined PLATFORM_POSIX
   27.52 -		dlclose(m_lib);
   27.53 -#endif
   27.54 -		m_lib = NULL;
   27.55 -	}
   27.56 -}
   27.57 -
   27.58 -CLibrary::CLibrary(LibraryHandle me)
   27.59 -{
   27.60 -	m_lib = me;
   27.61 -}
   27.62 -
   27.63 -void CLibrary::CloseLibrary()
   27.64 -{
   27.65 -	delete this;
   27.66 -}
   27.67 -
   27.68 -void *CLibrary::GetSymbolAddress(const char *symname)
   27.69 -{
   27.70 -#if defined PLATFORM_WINDOWS
   27.71 -	return GetProcAddress(m_lib, symname);
   27.72 -#elif defined PLATFORM_POSIX
   27.73 -	return dlsym(m_lib, symname);
   27.74 -#endif
   27.75 -}
   27.76 -
   27.77 -
   27.78 -/********************
   27.79 - ** Directory Code **
   27.80 - ********************/
   27.81 -
   27.82 -
   27.83 -CDirectory::CDirectory(const char *path)
   27.84 -{
   27.85 -#if defined PLATFORM_WINDOWS
   27.86 -	char newpath[PLATFORM_MAX_PATH];
   27.87 -	snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
   27.88 -	m_dir = FindFirstFileA(newpath, &m_fd);
   27.89 -	if (!IsValid())
   27.90 -	{
   27.91 -		m_fd.cFileName[0] = '\0';
   27.92 -	}
   27.93 -#elif defined PLATFORM_POSIX
   27.94 -	m_dir = opendir(path);
   27.95 -	if (IsValid())
   27.96 -	{
   27.97 -		/* :TODO: we need to read past "." and ".."! */
   27.98 -		ep = readdir(m_dir);
   27.99 -		snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
  27.100 -	} else {
  27.101 -		ep = NULL;
  27.102 -	}
  27.103 -#endif
  27.104 -}
  27.105 -
  27.106 -CDirectory::~CDirectory()
  27.107 -{
  27.108 -	if (IsValid())
  27.109 -	{
  27.110 -#if defined PLATFORM_WINDOWS
  27.111 -		FindClose(m_dir);
  27.112 -#elif defined PLATFORM_POSIX
  27.113 -		closedir(m_dir);
  27.114 -#endif
  27.115 -	}
  27.116 -}
  27.117 -
  27.118 -void CDirectory::NextEntry()
  27.119 -{
  27.120 -#if defined PLATFORM_WINDOWS
  27.121 -	if (FindNextFile(m_dir, &m_fd) == 0)
  27.122 -	{
  27.123 -		FindClose(m_dir);
  27.124 -		m_dir = INVALID_HANDLE_VALUE;
  27.125 -	}
  27.126 -#elif defined PLATFORM_POSIX
  27.127 -	if ((ep=readdir(m_dir)) == NULL)
  27.128 -	{
  27.129 -		closedir(m_dir);
  27.130 -		m_dir = NULL;
  27.131 -	}
  27.132 -#endif
  27.133 -}
  27.134 -
  27.135 -bool CDirectory::IsEntryValid()
  27.136 -{
  27.137 -	return IsValid();
  27.138 -}
  27.139 -
  27.140 -bool CDirectory::IsEntryDirectory()
  27.141 -{
  27.142 -#if defined PLATFORM_WINDOWS
  27.143 -	return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
  27.144 -#elif defined PLATFORM_LINUX
  27.145 -	char temppath[PLATFORM_MAX_PATH];
  27.146 -	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
  27.147 -	return g_LibSys.IsPathDirectory(temppath);
  27.148 -#endif
  27.149 -}
  27.150 -
  27.151 -bool CDirectory::IsEntryFile()
  27.152 -{
  27.153 -#if defined PLATFORM_WINDOWS
  27.154 -	return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
  27.155 -#elif defined PLATFORM_POSIX
  27.156 -	char temppath[PLATFORM_MAX_PATH];
  27.157 -	snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
  27.158 -	return g_LibSys.IsPathFile(temppath);
  27.159 -#endif
  27.160 -}
  27.161 -
  27.162 -const char *CDirectory::GetEntryName()
  27.163 -{
  27.164 -#if defined PLATFORM_WINDOWS
  27.165 -	return m_fd.cFileName;
  27.166 -#elif defined PLATFORM_LINUX
  27.167 -	return ep ? ep->d_name : "";
  27.168 -#endif
  27.169 -}
  27.170 -
  27.171 -bool CDirectory::MoreFiles()
  27.172 -{
  27.173 -	return IsValid();
  27.174 -}
  27.175 -
  27.176 -bool CDirectory::IsValid()
  27.177 -{
  27.178 -#if defined PLATFORM_WINDOWS
  27.179 -	return (m_dir != INVALID_HANDLE_VALUE);
  27.180 -#elif defined PLATFORM_LINUX
  27.181 -	return (m_dir != NULL);
  27.182 -#endif
  27.183 -}
  27.184 -
  27.185 -
  27.186 -/*************************
  27.187 - ** Library System Code **
  27.188 - *************************/
  27.189 -
  27.190 -
  27.191 -bool LibrarySystem::PathExists(const char *path)
  27.192 -{
  27.193 -#if defined PLATFORM_WINDOWS
  27.194 -	DWORD attr = GetFileAttributesA(path);
  27.195 -
  27.196 -	return (attr != INVALID_FILE_ATTRIBUTES);
  27.197 -#elif defined PLATFORM_POSIX
  27.198 -	struct stat s;
  27.199 -
  27.200 -	return (stat(path, &s) == 0);
  27.201 -#endif
  27.202 -}
  27.203 -
  27.204 -bool LibrarySystem::IsPathFile(const char *path)
  27.205 -{
  27.206 -#if defined PLATFORM_WINDOWS
  27.207 -	DWORD attr = GetFileAttributes(path);
  27.208 -
  27.209 -	if (attr == INVALID_FILE_ATTRIBUTES)
  27.210 -	{
  27.211 -		return false;
  27.212 -	}
  27.213 -
  27.214 -	if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
  27.215 -	{
  27.216 -		return false;
  27.217 -	}
  27.218 -
  27.219 -	return true;
  27.220 -#elif defined PLATFORM_LINUX
  27.221 -	struct stat s;
  27.222 -
  27.223 -	if (stat(path, &s) != 0)
  27.224 -	{
  27.225 -		return false;
  27.226 -	}
  27.227 -
  27.228 -	return S_ISREG(s.st_mode) ? true : false;
  27.229 -#endif
  27.230 -}
  27.231 -
  27.232 -bool LibrarySystem::IsPathDirectory(const char *path)
  27.233 -{
  27.234 -#if defined PLATFORM_WINDOWS
  27.235 -	DWORD attr = GetFileAttributes(path);
  27.236 -
  27.237 -	if (attr == INVALID_FILE_ATTRIBUTES)
  27.238 -	{
  27.239 -		return false;
  27.240 -	}
  27.241 -
  27.242 -	if (attr & FILE_ATTRIBUTE_DIRECTORY)
  27.243 -	{
  27.244 -		return true;
  27.245 -	}
  27.246 -
  27.247 -#elif defined PLATFORM_LINUX
  27.248 -	struct stat s;
  27.249 -
  27.250 -	if (stat(path, &s) != 0)
  27.251 -	{
  27.252 -		return false;
  27.253 -	}
  27.254 -
  27.255 -	if (S_ISDIR(s.st_mode))
  27.256 -	{
  27.257 -		return true;
  27.258 -	}
  27.259 -#endif
  27.260 -
  27.261 -	return false;
  27.262 -}
  27.263 -
  27.264 -IDirectory *LibrarySystem::OpenDirectory(const char *path)
  27.265 -{
  27.266 -	CDirectory *dir = new CDirectory(path);
  27.267 -
  27.268 -	if (!dir->IsValid())
  27.269 -	{
  27.270 -		delete dir;
  27.271 -		return NULL;
  27.272 -	}
  27.273 -
  27.274 -	return dir;
  27.275 -}
  27.276 -
  27.277 -void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
  27.278 -{
  27.279 -	if (error && maxlength)
  27.280 -	{
  27.281 -#if defined PLATFORM_WINDOWS
  27.282 -		DWORD dw = GetLastError();
  27.283 -		FormatMessageA(
  27.284 -			FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
  27.285 -			NULL,
  27.286 -			dw,
  27.287 -			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  27.288 -			(LPSTR)error,
  27.289 -			maxlength,
  27.290 -			NULL);
  27.291 -#elif defined PLATFORM_POSIX
  27.292 -		UTIL_Format(error, maxlength, "%s", strerror(errno));
  27.293 -#endif
  27.294 -	}
  27.295 -}
  27.296 -
  27.297 -void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
  27.298 -{
  27.299 -#if defined PLATFORM_WINDOWS
  27.300 -	GetPlatformError(buffer, maxlength);
  27.301 -#elif defined PLATFORM_POSIX
  27.302 -	if (buffer != NULL && maxlength)
  27.303 -	{
  27.304 -		strncopy(buffer, dlerror(), maxlength);
  27.305 -	}
  27.306 -#endif
  27.307 -}
  27.308 -
  27.309 -void LibrarySystem::CloseDirectory(IDirectory *dir)
  27.310 -{
  27.311 -	delete dir;
  27.312 -}
  27.313 -
  27.314 -ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
  27.315 -{
  27.316 -	LibraryHandle lib;
  27.317 -#if defined PLATFORM_WINDOWS
  27.318 -	lib = LoadLibraryA(path);
  27.319 -#elif defined PLATFORM_POSIX
  27.320 -	lib = dlopen(path, RTLD_NOW);
  27.321 -#endif
  27.322 -
  27.323 -	if (lib == NULL)
  27.324 -	{
  27.325 -		GetLoaderError(error, maxlength);
  27.326 -		return NULL;
  27.327 -	}
  27.328 -
  27.329 -	return new CLibrary(lib);
  27.330 -}
  27.331 -
  27.332 -size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
  27.333 -{
  27.334 -	va_list ap;
  27.335 -	va_start(ap, fmt);
  27.336 -	size_t mylen = vsnprintf(buffer, len, fmt, ap);
  27.337 -	va_end(ap);
  27.338 -
  27.339 -	if (mylen >= len)
  27.340 -	{
  27.341 -		mylen = len - 1;
  27.342 -		buffer[mylen] = '\0';
  27.343 -	}
  27.344 -
  27.345 -	for (size_t i=0; i<mylen; i++)
  27.346 -	{
  27.347 -		if (buffer[i] == PLATFORM_SEP_ALTCHAR)
  27.348 -		{
  27.349 -			buffer[i] = PLATFORM_SEP_CHAR;
  27.350 -		}
  27.351 -	}
  27.352 -
  27.353 -	return mylen;
  27.354 -}
  27.355 -
  27.356 -const char *LibrarySystem::GetFileExtension(const char *filename)
  27.357 -{
  27.358 -	size_t len, end;
  27.359 -
  27.360 -	len = strlen(filename);
  27.361 -
  27.362 -	/* Minimum string length for filename with ext would be 3; example: a.a */
  27.363 -	if (len < 3)
  27.364 -	{
  27.365 -		return NULL;
  27.366 -	}
  27.367 -
  27.368 -	end = len - 1;
  27.369 -
  27.370 -	for (size_t i = end; i <= end; i--)
  27.371 -	{
  27.372 -		if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
  27.373 -		{
  27.374 -			break;
  27.375 -		}
  27.376 -
  27.377 -		if (filename[i] == '.' && i != end && i != 0)
  27.378 -		{
  27.379 -			return &filename[++i];
  27.380 -		}
  27.381 -	}
  27.382 -
  27.383 -	return NULL;
  27.384 -}
  27.385 -
  27.386 -bool LibrarySystem::CreateFolder(const char *path)
  27.387 -{
  27.388 -#if defined PLATFORM_WINDOWS
  27.389 -	return (mkdir(path) != -1);
  27.390 -#elif defined PLATFORM_POSIX
  27.391 -	return (mkdir(path, 0775) != -1);
  27.392 -#endif
  27.393 -}
  27.394 -
  27.395 -size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path)
  27.396 -{
  27.397 -	size_t length = strlen(path);
  27.398 -
  27.399 -	for (size_t i = length - 1;
  27.400 -		 i >= 0 && i <= length - 1;
  27.401 -		 i--)
  27.402 -	{
  27.403 -		if (path[i] == '/' 
  27.404 -#if defined PLATFORM_WINDOWS
  27.405 -			|| path[i] == '\\'
  27.406 -#endif
  27.407 -			)
  27.408 -		{
  27.409 -			return UTIL_Format(buffer, maxlength, "%s", &path[i+1]);
  27.410 -		}
  27.411 -	}
  27.412 -
  27.413 -	/* We scanned and found no path separator */
  27.414 -	return UTIL_Format(buffer, maxlength, "%s", path);
  27.415 -}
  27.416 -
  27.417 -bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)
  27.418 -{
  27.419 -#ifdef PLATFORM_WINDOWS
  27.420 -	struct _stat s;
  27.421 -	if (_stat(path, &s) != 0)
  27.422 -#elif defined PLATFORM_POSIX
  27.423 -	struct stat s;
  27.424 -	if (stat(path, &s) != 0)
  27.425 -#endif
  27.426 -	{
  27.427 -		return false;
  27.428 -	}
  27.429 -
  27.430 -	if (type == FileTime_LastAccess)
  27.431 -	{
  27.432 -		*pTime = s.st_atime;
  27.433 -	}
  27.434 -	else if (type == FileTime_Created)
  27.435 -	{
  27.436 -		*pTime = s.st_ctime;
  27.437 -	}
  27.438 -	else if (type == FileTime_LastChange)
  27.439 -	{
  27.440 -		*pTime = s.st_mtime;
  27.441 -	}
  27.442 -
  27.443 -	return true;
  27.444 -}
    28.1 --- a/core/systems/LibrarySys.h	Mon Nov 24 08:25:36 2008 -0600
    28.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.3 @@ -1,103 +0,0 @@
    28.4 -/**
    28.5 - * vim: set ts=4 :
    28.6 - * =============================================================================
    28.7 - * SourceMod
    28.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    28.9 - * =============================================================================
   28.10 - *
   28.11 - * This program is free software; you can redistribute it and/or modify it under
   28.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   28.13 - * Free Software Foundation.
   28.14 - * 
   28.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   28.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   28.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   28.18 - * details.
   28.19 - *
   28.20 - * You should have received a copy of the GNU General Public License along with
   28.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   28.22 - *
   28.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   28.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   28.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   28.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   28.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   28.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   28.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   28.30 - * or <http://www.sourcemod.net/license.php>.
   28.31 - *
   28.32 - * Version: $Id$
   28.33 - */
   28.34 -
   28.35 -#ifndef _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
   28.36 -#define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
   28.37 -
   28.38 -#include <ILibrarySys.h>
   28.39 -#include "sm_platform.h"
   28.40 -
   28.41 -using namespace SourceMod;
   28.42 -
   28.43 -#if defined PLATFORM_WINDOWS
   28.44 -typedef HMODULE		LibraryHandle;
   28.45 -#elif defined PLATFORM_POSIX
   28.46 -typedef void *		LibraryHandle;
   28.47 -#endif
   28.48 -
   28.49 -class CDirectory : public IDirectory
   28.50 -{
   28.51 -public:
   28.52 -	CDirectory(const char *path);
   28.53 -	~CDirectory();
   28.54 -public:
   28.55 -	bool MoreFiles();
   28.56 -	void NextEntry();
   28.57 -	const char *GetEntryName();
   28.58 -	bool IsEntryDirectory();
   28.59 -	bool IsEntryFile();
   28.60 -	bool IsEntryValid();
   28.61 -public:
   28.62 -	bool IsValid();
   28.63 -private:
   28.64 -#if defined PLATFORM_WINDOWS
   28.65 -	HANDLE m_dir;
   28.66 -	WIN32_FIND_DATAA m_fd;
   28.67 -#elif defined PLATFORM_POSIX
   28.68 -	DIR *m_dir;
   28.69 -	struct dirent *ep;
   28.70 -	char m_origpath[PLATFORM_MAX_PATH];
   28.71 -#endif
   28.72 -};
   28.73 -
   28.74 -class CLibrary : public ILibrary
   28.75 -{
   28.76 -public:
   28.77 -	CLibrary(LibraryHandle me);
   28.78 -	~CLibrary();
   28.79 -public:
   28.80 -	void CloseLibrary();
   28.81 -	void *GetSymbolAddress(const char *symname);
   28.82 -private:
   28.83 -	LibraryHandle m_lib;
   28.84 -};
   28.85 -
   28.86 -class LibrarySystem : public ILibrarySys
   28.87 -{
   28.88 -public:
   28.89 -	ILibrary *OpenLibrary(const char *path, char *error, size_t maxlength);
   28.90 -	IDirectory *OpenDirectory(const char *path);
   28.91 -	void CloseDirectory(IDirectory *dir);
   28.92 -	bool PathExists(const char *path);
   28.93 -	bool IsPathFile(const char *path);
   28.94 -	bool IsPathDirectory(const char *path);
   28.95 -	void GetPlatformError(char *error, size_t maxlength);
   28.96 -	size_t PathFormat(char *buffer, size_t len, const char *fmt, ...);
   28.97 -	const char *GetFileExtension(const char *filename);
   28.98 -	bool CreateFolder(const char *path);
   28.99 -	size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path);
  28.100 -	bool FileTime(const char *path, FileTimeType type, time_t *pTime);
  28.101 -	void GetLoaderError(char *buffer, size_t maxlength);
  28.102 -};
  28.103 -
  28.104 -extern LibrarySystem g_LibSys;
  28.105 -
  28.106 -#endif //_INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
    29.1 --- a/core/systems/PluginInfoDatabase.cpp	Mon Nov 24 08:25:36 2008 -0600
    29.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.3 @@ -1,349 +0,0 @@
    29.4 -/**
    29.5 - * vim: set ts=4 :
    29.6 - * =============================================================================
    29.7 - * SourceMod
    29.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    29.9 - * =============================================================================
   29.10 - *
   29.11 - * This program is free software; you can redistribute it and/or modify it under
   29.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   29.13 - * Free Software Foundation.
   29.14 - * 
   29.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   29.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   29.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   29.18 - * details.
   29.19 - *
   29.20 - * You should have received a copy of the GNU General Public License along with
   29.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   29.22 - *
   29.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   29.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   29.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   29.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   29.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   29.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   29.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   29.30 - * or <http://www.sourcemod.net/license.php>.
   29.31 - *
   29.32 - * Version: $Id$
   29.33 - */
   29.34 -
   29.35 -#include <stdarg.h>
   29.36 -#include <string.h>
   29.37 -#include "PluginInfoDatabase.h"
   29.38 -#include "PluginSys.h"
   29.39 -
   29.40 -void PluginSettings::Init()
   29.41 -{
   29.42 -	name = -1;
   29.43 -	pause_val = false;
   29.44 -	type_val = PluginType_MapUpdated;
   29.45 -	optarray = -1;
   29.46 -	opts_num = 0;
   29.47 -	opts_size = 0;
   29.48 -	blockload_val = false;
   29.49 -}
   29.50 -
   29.51 -/**
   29.52 - * :TODO: write the logger, make these errors log instead of being static
   29.53 - * NOTE: once we do that, we will have to change some code to ignore sections
   29.54 - */
   29.55 -
   29.56 -CPluginInfoDatabase::CPluginInfoDatabase()
   29.57 -{
   29.58 -	m_strtab = NULL;
   29.59 -	m_infodb_count = 0;
   29.60 -	m_infodb_size = 0;
   29.61 -	m_infodb = -1;
   29.62 -}
   29.63 -
   29.64 -CPluginInfoDatabase::~CPluginInfoDatabase()
   29.65 -{
   29.66 -	delete m_strtab;
   29.67 -}
   29.68 -
   29.69 -void CPluginInfoDatabase::ReadSMC_ParseStart()
   29.70 -{
   29.71 -	/* Create or reset our string table */
   29.72 -	if (m_strtab)
   29.73 -	{
   29.74 -		m_strtab->Reset();
   29.75 -	} else {
   29.76 -		m_strtab = new BaseStringTable(1024);
   29.77 -	}
   29.78 -
   29.79 -	/* Set our internal states to the beginning */
   29.80 -	in_plugins = false;
   29.81 -	cur_plugin = -1;
   29.82 -	in_options = false;
   29.83 -	m_infodb_size = 0;
   29.84 -	m_infodb_count = 0;
   29.85 -	m_infodb = -1;
   29.86 -}
   29.87 -
   29.88 -SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
   29.89 -{
   29.90 -	char buffer[512];
   29.91 -	va_list ap;
   29.92 -
   29.93 -	va_start(ap, fmt);
   29.94 -	vsnprintf(buffer, sizeof(buffer), fmt, ap);
   29.95 -	va_end(ap);
   29.96 -
   29.97 -	m_errmsg = m_strtab->AddString(buffer);
   29.98 -
   29.99 -	return SMCResult_HaltFail;
  29.100 -}
  29.101 -
  29.102 -unsigned int CPluginInfoDatabase::GetSettingsNum()
  29.103 -{
  29.104 -	return m_infodb_count;
  29.105 -}
  29.106 -
  29.107 -PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
  29.108 -{
  29.109 -	BaseMemTable *memtab = m_strtab->GetMemTable();
  29.110 -	int *table = (int *)memtab->GetAddress(m_infodb);
  29.111 -
  29.112 -	if (!table || index >= m_infodb_count)
  29.113 -	{
  29.114 -		return NULL;
  29.115 -	}
  29.116 -
  29.117 -	PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]);
  29.118 -
  29.119 -	const char *name = m_strtab->GetString(plugin->name);
  29.120 -
  29.121 -	if (!name)
  29.122 -	{
  29.123 -		return NULL;
  29.124 -	}
  29.125 -
  29.126 -	if (!g_PluginSys.TestAliasMatch(name, filename))
  29.127 -	{
  29.128 -		return NULL;
  29.129 -	}
  29.130 -
  29.131 -	return plugin;
  29.132 -}
  29.133 -
  29.134 -void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
  29.135 -{
  29.136 -	PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
  29.137 -	if (!table)
  29.138 -	{
  29.139 -		*key = NULL;
  29.140 -		*val = NULL;
  29.141 -		return;
  29.142 -	}
  29.143 -
  29.144 -	if (opt_num >= settings->opts_num)
  29.145 -	{
  29.146 -		*key = NULL;
  29.147 -		*val = NULL;
  29.148 -		return;
  29.149 -	}
  29.150 -
  29.151 -	*key = m_strtab->GetString(table[opt_num].key);
  29.152 -	*val = m_strtab->GetString(table[opt_num].val);
  29.153 -}
  29.154 -
  29.155 -SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
  29.156 -{
  29.157 -	if (cur_plugin != -1)
  29.158 -	{
  29.159 -		PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
  29.160 -		if (!in_options)
  29.161 -		{
  29.162 -			if (strcmp(key, "pause") == 0)
  29.163 -			{
  29.164 -				if (strcasecmp(value, "yes") == 0)
  29.165 -				{
  29.166 -					plugin->pause_val = true;
  29.167 -				} 
  29.168 -				else 
  29.169 -				{
  29.170 -					plugin->pause_val = false;
  29.171 -				}
  29.172 -			} 
  29.173 -			else if (strcmp(key, "lifetime") == 0) 
  29.174 -			{
  29.175 -				if (strcasecmp(value, "private") == 0)
  29.176 -				{
  29.177 -					plugin->type_val = PluginType_Private;
  29.178 -				} 
  29.179 -				else if (strcasecmp(value, "mapsync") == 0) 
  29.180 -				{
  29.181 -					plugin->type_val = PluginType_MapUpdated;
  29.182 -				}
  29.183 -				else if (strcasecmp(value, "maponly") == 0) 
  29.184 -				{
  29.185 -					plugin->type_val = PluginType_MapOnly;
  29.186 -				}
  29.187 -				else if (strcasecmp(value, "global") == 0) 
  29.188 -				{
  29.189 -					plugin->type_val = PluginType_Global;
  29.190 -				}
  29.191 -				else 
  29.192 -				{
  29.193 -					return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
  29.194 -				}
  29.195 -			}
  29.196 -			else if (strcmp(key, "blockload") == 0) 
  29.197 -			{
  29.198 -				plugin->blockload_val = true;
  29.199 -			} 
  29.200 -			else 
  29.201 -			{
  29.202 -				return MakeError("Unknown property key: \"%s\"", key);
  29.203 -			}
  29.204 -		}
  29.205 -		else 
  29.206 -		{
  29.207 -			/* Cache every option, valid or not */
  29.208 -			int keyidx = m_strtab->AddString(key);
  29.209 -			int validx = m_strtab->AddString(value);
  29.210 -			PluginOpts *table;
  29.211 -			BaseMemTable *memtab = m_strtab->GetMemTable();
  29.212 -			plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
  29.213 -			if (plugin->opts_num + 1 > plugin->opts_size)
  29.214 -			{
  29.215 -				unsigned int oldsize = plugin->opts_size;
  29.216 -				if (oldsize == 0)
  29.217 -				{
  29.218 -					//right now we don't have many
  29.219 -					plugin->opts_size = 2;
  29.220 -				} 
  29.221 -				else
  29.222 -				{
  29.223 -					plugin->opts_size *= 2;
  29.224 -				}
  29.225 -				int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
  29.226 -				/* in case it resized */
  29.227 -				plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
  29.228 -				if (plugin->optarray != -1)
  29.229 -				{
  29.230 -					void *oldtable = memtab->GetAddress(plugin->optarray);
  29.231 -					memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
  29.232 -				}
  29.233 -				plugin->optarray = newidx;
  29.234 -			}
  29.235 -			else
  29.236 -			{
  29.237 -				table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
  29.238 -			}
  29.239 -			PluginOpts *opt = &table[plugin->opts_num++];
  29.240 -			opt->key = keyidx;
  29.241 -			opt->val = validx;
  29.242 -		}
  29.243 -	}
  29.244 -	else if (in_plugins)
  29.245 -	{
  29.246 -		return MakeError("Unknown property key: \"%s\"", key);
  29.247 -	}
  29.248 -	else 
  29.249 -	{
  29.250 -		/* Ignore anything we don't know about! */
  29.251 -	}
  29.252 -
  29.253 -	return SMCResult_Continue;
  29.254 -}
  29.255 -
  29.256 -SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
  29.257 -{
  29.258 -	if (in_plugins)
  29.259 -	{
  29.260 -		if (cur_plugin != -1)
  29.261 -		{
  29.262 -			if (in_options)
  29.263 -			{
  29.264 -				in_options = false;
  29.265 -			}
  29.266 -			else 
  29.267 -			{
  29.268 -				/* If the plugin is ending, add it to the table */
  29.269 -				BaseMemTable *memtab = m_strtab->GetMemTable();
  29.270 -				int *table;
  29.271 -				if (m_infodb_count + 1 > m_infodb_size)
  29.272 -				{
  29.273 -					unsigned int oldsize = m_infodb_size;
  29.274 -					if (!m_infodb_size)
  29.275 -					{
  29.276 -						m_infodb_size = 8;
  29.277 -					}
  29.278 -					else 
  29.279 -					{
  29.280 -						m_infodb_size *= 2;
  29.281 -					}
  29.282 -					int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
  29.283 -					if (m_infodb != -1)
  29.284 -					{
  29.285 -						void *oldtable = (int *)memtab->GetAddress(m_infodb);
  29.286 -						memcpy(table, oldtable, oldsize * sizeof(int));
  29.287 -					}
  29.288 -					m_infodb = newidx;
  29.289 -				}
  29.290 -				else 
  29.291 -				{
  29.292 -					table = (int *)memtab->GetAddress(m_infodb);
  29.293 -				}
  29.294 -				/* Assign to table and scrap the current plugin */
  29.295 -				table[m_infodb_count++] = cur_plugin;
  29.296 -				cur_plugin = -1;
  29.297 -			}
  29.298 -		}
  29.299 -		else 
  29.300 -		{
  29.301 -			in_plugins = false;
  29.302 -		}
  29.303 -	}
  29.304 -
  29.305 -	return SMCResult_Continue;
  29.306 -}
  29.307 -
  29.308 -SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
  29.309 -{
  29.310 -	if (!in_plugins)
  29.311 -	{
  29.312 -		/* If we're not in the main Plugins section, and we don't get it for the name, error out */
  29.313 -		if (strcmp(name, "Plugins") != 0)
  29.314 -		{
  29.315 -			return MakeError("Unknown root section: \"%s\"", name);
  29.316 -		}
  29.317 -		else 
  29.318 -		{
  29.319 -			/* Otherwise set our states */
  29.320 -			in_plugins = true;
  29.321 -			cur_plugin = -1;
  29.322 -			in_options = false;
  29.323 -		}
  29.324 -	}
  29.325 -	else
  29.326 -	{
  29.327 -		if (cur_plugin == -1)
  29.328 -		{
  29.329 -			/* If we get a plugin node and we don't have a current plugin, create a new one */
  29.330 -			PluginSettings *plugin;
  29.331 -			int i_name = m_strtab->AddString(name);
  29.332 -			cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
  29.333 -			plugin->Init();
  29.334 -			plugin->name = i_name;
  29.335 -			in_options = false;
  29.336 -		} 
  29.337 -		else 
  29.338 -		{
  29.339 -			if (!in_options && strcmp(name, "Options") == 0)
  29.340 -			{
  29.341 -				in_options = true;
  29.342 -			}
  29.343 -			else
  29.344 -			{
  29.345 -				return MakeError("Unknown plugin sub-section: \"%s\"", name);
  29.346 -			}
  29.347 -		}
  29.348 -	}
  29.349 -
  29.350 -	return SMCResult_Continue;
  29.351 -}
  29.352 -
    30.1 --- a/core/systems/PluginInfoDatabase.h	Mon Nov 24 08:25:36 2008 -0600
    30.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.3 @@ -1,106 +0,0 @@
    30.4 -/**
    30.5 - * vim: set ts=4 :
    30.6 - * =============================================================================
    30.7 - * SourceMod
    30.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    30.9 - * =============================================================================
   30.10 - *
   30.11 - * This program is free software; you can redistribute it and/or modify it under
   30.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   30.13 - * Free Software Foundation.
   30.14 - * 
   30.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   30.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   30.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   30.18 - * details.
   30.19 - *
   30.20 - * You should have received a copy of the GNU General Public License along with
   30.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   30.22 - *
   30.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   30.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   30.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   30.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   30.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   30.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   30.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   30.30 - * or <http://www.sourcemod.net/license.php>.
   30.31 - *
   30.32 - * Version: $Id$
   30.33 - */
   30.34 -
   30.35 -#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
   30.36 -#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
   30.37 -
   30.38 -/**
   30.39 - * This file parses plugin_settings.cfg and stores the information in cached memory.
   30.40 - * It provides simplistic abstraction to retrieving the info.
   30.41 - * :TODO: currently untested
   30.42 - */
   30.43 -
   30.44 -#include "sm_memtable.h"
   30.45 -#include "ITextParsers.h"
   30.46 -#include "IPluginSys.h"
   30.47 -#include "sm_globals.h"
   30.48 -
   30.49 -struct PluginOpts
   30.50 -{
   30.51 -	int key;
   30.52 -	int val;
   30.53 -};
   30.54 -
   30.55 -struct PluginSettings
   30.56 -{
   30.57 -	void Init();
   30.58 -	int name;
   30.59 -	bool pause_val;
   30.60 -	PluginType type_val;
   30.61 -	int optarray;
   30.62 -	size_t opts_num;
   30.63 -	size_t opts_size;
   30.64 -	bool blockload_val;
   30.65 -};
   30.66 -
   30.67 -class CPluginInfoDatabase : public ITextListener_SMC
   30.68 -{
   30.69 -public:
   30.70 -	CPluginInfoDatabase();
   30.71 -	~CPluginInfoDatabase();
   30.72 -public: //ITextListener_SMC
   30.73 -	void ReadSMC_ParseStart();
   30.74 -	SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
   30.75 -	SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
   30.76 -	SMCResult ReadSMC_LeavingSection(const SMCStates *states);
   30.77 -public:
   30.78 -	/**
   30.79 -	 * Returns the number of plugin settings available.
   30.80 -	 */
   30.81 -	unsigned int GetSettingsNum();
   30.82 -
   30.83 -	/** 
   30.84 -	 * Given an index, returns the plugin settings block if the filename matches.
   30.85 -	 * Otherwise, returns NULL.
   30.86 -	 */
   30.87 -	PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
   30.88 -
   30.89 -	/** 
   30.90 -	 *  Given a plugin settings struct and an index,
   30.91 -	 * returns the given JIT key/value option pair at that index.
   30.92 -	 * If the input is invalid, key and val will be set to NULL.
   30.93 -	 */
   30.94 -	void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
   30.95 -private:
   30.96 -	SMCResult MakeError(const char *fmt, ...);
   30.97 -private:
   30.98 -	BaseStringTable *m_strtab;
   30.99 -	int m_errmsg;
  30.100 -	bool in_plugins;
  30.101 -	bool in_options;
  30.102 -	int m_infodb;
  30.103 -	size_t m_infodb_count;
  30.104 -	size_t m_infodb_size;
  30.105 -	int cur_plugin;
  30.106 -};
  30.107 -
  30.108 -
  30.109 -#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
    31.1 --- a/core/systems/PluginSys.cpp	Mon Nov 24 08:25:36 2008 -0600
    31.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.3 @@ -1,2626 +0,0 @@
    31.4 -/**
    31.5 - * vim: set ts=4 :
    31.6 - * =============================================================================
    31.7 - * SourceMod
    31.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    31.9 - * =============================================================================
   31.10 - *
   31.11 - * This program is free software; you can redistribute it and/or modify it under
   31.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   31.13 - * Free Software Foundation.
   31.14 - * 
   31.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   31.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   31.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   31.18 - * details.
   31.19 - *
   31.20 - * You should have received a copy of the GNU General Public License along with
   31.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   31.22 - *
   31.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   31.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   31.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   31.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   31.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   31.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   31.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   31.30 - * or <http://www.sourcemod.net/license.php>.
   31.31 - *
   31.32 - * Version: $Id$
   31.33 - */
   31.34 -
   31.35 -#include <stdio.h>
   31.36 -#include "PluginSys.h"
   31.37 -#include "ShareSys.h"
   31.38 -#include "LibrarySys.h"
   31.39 -#include "HandleSys.h"
   31.40 -#include "ForwardSys.h"
   31.41 -#include "sourcemm_api.h"
   31.42 -#include "sourcemod.h"
   31.43 -#include "TextParsers.h"
   31.44 -#include "Logger.h"
   31.45 -#include "ExtensionSys.h"
   31.46 -#include "sm_srvcmds.h"
   31.47 -#include "sm_stringutil.h"
   31.48 -#include "ConCmdManager.h"
   31.49 -#include "PlayerManager.h"
   31.50 -#include "CoreConfig.h"
   31.51 -#include "Translator.h"
   31.52 -
   31.53 -CPluginManager g_PluginSys;
   31.54 -HandleType_t g_PluginType = 0;
   31.55 -IdentityType_t g_PluginIdent = 0;
   31.56 -
   31.57 -CPlugin::CPlugin(const char *file)
   31.58 -{
   31.59 -	static int MySerial = 0;
   31.60 -
   31.61 -	m_type = PluginType_Private;
   31.62 -	m_status = Plugin_Uncompiled;
   31.63 -	m_serial = ++MySerial;
   31.64 -	m_pRuntime = NULL;
   31.65 -	m_errormsg[256] = '\0';
   31.66 -	snprintf(m_filename, sizeof(m_filename), "%s", file);
   31.67 -	m_handle = 0;
   31.68 -	m_ident = NULL;
   31.69 -	m_pProps = sm_trie_create();
   31.70 -	m_FakeNativesMissing = false;
   31.71 -	m_LibraryMissing = false;
   31.72 -	m_bGotAllLoaded = false;
   31.73 -	m_pPhrases = g_Translator.CreatePhraseCollection();
   31.74 -	m_MaxClientsVar = NULL;
   31.75 -}
   31.76 -
   31.77 -CPlugin::~CPlugin()
   31.78 -{
   31.79 -	if (m_handle)
   31.80 -	{
   31.81 -		HandleSecurity sec;
   31.82 -		sec.pOwner = g_PluginSys.GetIdentity();
   31.83 -		sec.pIdentity = sec.pOwner;
   31.84 -
   31.85 -		g_HandleSys.FreeHandle(m_handle, &sec);
   31.86 -		g_ShareSys.DestroyIdentity(m_ident);
   31.87 -	}
   31.88 -
   31.89 -	if (m_pRuntime != NULL)
   31.90 -	{
   31.91 -		delete m_pRuntime;
   31.92 -		m_pRuntime = NULL;
   31.93 -	}
   31.94 -
   31.95 -	if (m_pProps)
   31.96 -	{
   31.97 -		sm_trie_destroy(m_pProps);
   31.98 -	}
   31.99 -	for (size_t i=0; i<m_configs.size(); i++)
  31.100 -	{
  31.101 -		delete m_configs[i];
  31.102 -	}
  31.103 -	m_configs.clear();
  31.104 -	if (m_pPhrases != NULL)
  31.105 -	{
  31.106 -		m_pPhrases->Destroy();
  31.107 -		m_pPhrases = NULL;
  31.108 -	}
  31.109 -}
  31.110 -
  31.111 -void CPlugin::InitIdentity()
  31.112 -{
  31.113 -	if (!m_handle)
  31.114 -	{
  31.115 -		m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
  31.116 -		m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
  31.117 -		m_pRuntime->GetDefaultContext()->SetKey(1, m_ident);
  31.118 -		m_pRuntime->GetDefaultContext()->SetKey(2, (IPlugin *)this);
  31.119 -	}
  31.120 -}
  31.121 -
  31.122 -unsigned int CPlugin::CalcMemUsage()
  31.123 -{
  31.124 -	unsigned int base_size = 
  31.125 -		sizeof(CPlugin) 
  31.126 -		+ sizeof(IdentityToken_t)
  31.127 -		+ (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig)))
  31.128 -		+ sm_trie_mem_usage(m_pProps);
  31.129 -
  31.130 -	for (unsigned int i = 0; i < m_configs.size(); i++)
  31.131 -	{
  31.132 -		base_size += m_configs[i]->autocfg.size();
  31.133 -		base_size += m_configs[i]->folder.size();
  31.134 -	}
  31.135 -
  31.136 -	for (List<String>::iterator i = m_Libraries.begin();
  31.137 -		 i != m_Libraries.end();
  31.138 -		 i++)
  31.139 -	{
  31.140 -		base_size += (*i).size();
  31.141 -	}
  31.142 -
  31.143 -	for (List<String>::iterator i = m_RequiredLibs.begin();
  31.144 -		 i != m_RequiredLibs.end();
  31.145 -		 i++)
  31.146 -	{
  31.147 -		base_size += (*i).size();
  31.148 -	}
  31.149 -
  31.150 -	return base_size;
  31.151 -}
  31.152 -
  31.153 -Handle_t CPlugin::GetMyHandle()
  31.154 -{
  31.155 -	return m_handle;
  31.156 -}
  31.157 -
  31.158 -CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
  31.159 -{
  31.160 -	char fullpath[PLATFORM_MAX_PATH];
  31.161 -	g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file);
  31.162 -	FILE *fp = fopen(fullpath, "rb");
  31.163 -
  31.164 -	CPlugin *pPlugin = new CPlugin(file);
  31.165 -
  31.166 -	if (!fp)
  31.167 -	{
  31.168 -		if (error)
  31.169 -		{
  31.170 -			snprintf(error, maxlength, "Unable to open file");
  31.171 -		}
  31.172 -		pPlugin->m_status = Plugin_BadLoad;
  31.173 -		return pPlugin;
  31.174 -	}
  31.175 -
  31.176 -	fclose(fp);
  31.177 -
  31.178 -	return pPlugin;
  31.179 -}
  31.180 -
  31.181 -bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */)
  31.182 -{
  31.183 -	bool exists = sm_trie_retrieve(m_pProps, prop, ptr);
  31.184 -
  31.185 -	if (exists && remove)
  31.186 -	{
  31.187 -		sm_trie_delete(m_pProps, prop);
  31.188 -	}
  31.189 -
  31.190 -	return exists;
  31.191 -}
  31.192 -
  31.193 -bool CPlugin::SetProperty(const char *prop, void *ptr)
  31.194 -{
  31.195 -	return sm_trie_insert(m_pProps, prop, ptr);
  31.196 -}
  31.197 -
  31.198 -IPluginRuntime *CPlugin::GetRuntime()
  31.199 -{
  31.200 -	return m_pRuntime;
  31.201 -}
  31.202 -
  31.203 -void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
  31.204 -{
  31.205 -	PluginStatus old_status = m_status;
  31.206 -	m_status = status;
  31.207 -
  31.208 -	if (old_status == Plugin_Running)
  31.209 -	{
  31.210 -		/* Tell everyone we're now paused */
  31.211 -		g_PluginSys._SetPauseState(this, true);
  31.212 -	}
  31.213 -
  31.214 -	va_list ap;
  31.215 -	va_start(ap, error_fmt);
  31.216 -	vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
  31.217 -	va_end(ap);
  31.218 -
  31.219 -	if (m_pRuntime != NULL)
  31.220 -	{
  31.221 -		m_pRuntime->SetPauseState(true);
  31.222 -	}
  31.223 -}
  31.224 -
  31.225 -bool CPlugin::UpdateInfo()
  31.226 -{
  31.227 -	/* Now grab the info */
  31.228 -	uint32_t idx;
  31.229 -	IPluginContext *base = GetBaseContext();
  31.230 -	int err = base->FindPubvarByName("myinfo", &idx);
  31.231 -
  31.232 -	memset(&m_info, 0, sizeof(m_info));
  31.233 -
  31.234 -	if (err == SP_ERROR_NONE)
  31.235 -	{
  31.236 -		struct sm_plugininfo_c_t
  31.237 -		{
  31.238 -			cell_t name;
  31.239 -			cell_t description;
  31.240 -			cell_t author;
  31.241 -			cell_t version;
  31.242 -			cell_t url;
  31.243 -		};
  31.244 -		sm_plugininfo_c_t *cinfo;
  31.245 -		cell_t local_addr;
  31.246 -
  31.247 -		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
  31.248 -		base->LocalToString(cinfo->name, (char **)&m_info.name);
  31.249 -		base->LocalToString(cinfo->description, (char **)&m_info.description);
  31.250 -		base->LocalToString(cinfo->author, (char **)&m_info.author);
  31.251 -		base->LocalToString(cinfo->url, (char **)&m_info.url);
  31.252 -		base->LocalToString(cinfo->version, (char **)&m_info.version);
  31.253 -	}
  31.254 -
  31.255 -	m_info.author = m_info.author ? m_info.author : "";
  31.256 -	m_info.description = m_info.description ? m_info.description : "";
  31.257 -	m_info.name = m_info.name ? m_info.name : "";
  31.258 -	m_info.url = m_info.url ? m_info.url : "";
  31.259 -	m_info.version = m_info.version ? m_info.version : "";
  31.260 -
  31.261 -	if ((err = base->FindPubvarByName("__version", &idx)) == SP_ERROR_NONE)
  31.262 -	{
  31.263 -		struct __version_info
  31.264 -		{
  31.265 -			cell_t version;
  31.266 -			cell_t filevers;
  31.267 -			cell_t date;
  31.268 -			cell_t time;
  31.269 -		};
  31.270 -		__version_info *info;
  31.271 -		cell_t local_addr;
  31.272 -		const char *pDate, *pTime, *pFileVers;
  31.273 -
  31.274 -		pDate = "";
  31.275 -		pTime = "";
  31.276 -
  31.277 -		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
  31.278 -		m_FileVersion = info->version;
  31.279 -		if (m_FileVersion >= 3)
  31.280 -		{
  31.281 -			base->LocalToString(info->date, (char **)&pDate);
  31.282 -			base->LocalToString(info->time, (char **)&pTime);
  31.283 -			UTIL_Format(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
  31.284 -		}
  31.285 -		if (m_FileVersion > 4)
  31.286 -		{
  31.287 -			base->LocalToString(info->filevers, (char **)&pFileVers);
  31.288 -			SetErrorState(Plugin_Failed, "Newer SourceMod required (%s or higher)", pFileVers);
  31.289 -			return false;
  31.290 -		}
  31.291 -	}
  31.292 -	else
  31.293 -	{
  31.294 -		m_FileVersion = 0;
  31.295 -	}
  31.296 -
  31.297 -	if ((err = base->FindPubvarByName("MaxClients", &idx)) == SP_ERROR_NONE)
  31.298 -	{
  31.299 -		base->GetPubvarByIndex(idx, &m_MaxClientsVar);
  31.300 -	}
  31.301 -
  31.302 -	return true;
  31.303 -}
  31.304 -
  31.305 -void CPlugin::SyncMaxClients(int max_clients)
  31.306 -{
  31.307 -	if (m_MaxClientsVar == NULL)
  31.308 -	{
  31.309 -		return;
  31.310 -	}
  31.311 -
  31.312 -	*m_MaxClientsVar->offs = max_clients;
  31.313 -}
  31.314 -
  31.315 -void CPlugin::Call_OnPluginStart()
  31.316 -{
  31.317 -	if (m_status != Plugin_Loaded)
  31.318 -	{
  31.319 -		return;
  31.320 -	}
  31.321 -
  31.322 -	m_status = Plugin_Running;
  31.323 -
  31.324 -	SyncMaxClients(g_Players.MaxClients());
  31.325 -
  31.326 -	cell_t result;
  31.327 -	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginStart");
  31.328 -	if (!pFunction)
  31.329 -	{
  31.330 -		return;
  31.331 -	}
  31.332 -
  31.333 -	int err;
  31.334 -	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
  31.335 -	{
  31.336 -		SetErrorState(Plugin_Error, "Error detected in plugin startup (see error logs)");
  31.337 -	}
  31.338 -}
  31.339 -
  31.340 -void CPlugin::Call_OnPluginEnd()
  31.341 -{
  31.342 -	if (m_status > Plugin_Paused)
  31.343 -	{
  31.344 -		return;
  31.345 -	}
  31.346 -
  31.347 -	cell_t result;
  31.348 -	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginEnd");
  31.349 -	if (!pFunction)
  31.350 -	{
  31.351 -		return;
  31.352 -	}
  31.353 -
  31.354 -	pFunction->Execute(&result);
  31.355 -}
  31.356 -
  31.357 -void CPlugin::Call_OnAllPluginsLoaded()
  31.358 -{
  31.359 -	if (m_status > Plugin_Paused)
  31.360 -	{
  31.361 -		return;
  31.362 -	}
  31.363 -
  31.364 -	if (m_bGotAllLoaded)
  31.365 -	{
  31.366 -		return;
  31.367 -	}
  31.368 -
  31.369 -	m_bGotAllLoaded = true;
  31.370 -
  31.371 -	cell_t result;
  31.372 -	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnAllPluginsLoaded");
  31.373 -	if (pFunction != NULL)
  31.374 -	{
  31.375 -		pFunction->Execute(&result);
  31.376 -	}
  31.377 -
  31.378 -	if (g_OnMapStarted)
  31.379 -	{
  31.380 -		if ((pFunction = m_pRuntime->GetFunctionByName("OnMapStart")) != NULL)
  31.381 -		{
  31.382 -			pFunction->Execute(NULL);
  31.383 -		}
  31.384 -	}
  31.385 -
  31.386 -	if (SM_AreConfigsExecuted())
  31.387 -	{
  31.388 -		SM_ExecuteForPlugin(GetBaseContext());
  31.389 -	}
  31.390 -}
  31.391 -
  31.392 -bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
  31.393 -{
  31.394 -	if (m_status != Plugin_Created)
  31.395 -	{
  31.396 -		return false;
  31.397 -	}
  31.398 -
  31.399 -	m_status = Plugin_Loaded;
  31.400 -
  31.401 -	int err;
  31.402 -	cell_t result;
  31.403 -	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("AskPluginLoad");
  31.404 -
  31.405 -	if (!pFunction)
  31.406 -	{
  31.407 -		return true;
  31.408 -	}
  31.409 -
  31.410 -	pFunction->PushCell(m_handle);
  31.411 -	pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
  31.412 -	pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
  31.413 -	pFunction->PushCell(maxlength);
  31.414 -	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
  31.415 -	{
  31.416 -		return false;
  31.417 -	}
  31.418 -
  31.419 -	if (!result || m_status != Plugin_Loaded)
  31.420 -	{
  31.421 -		return false;
  31.422 -	}
  31.423 -
  31.424 -	return true;
  31.425 -}
  31.426 -
  31.427 -void *CPlugin::GetPluginStructure()
  31.428 -{
  31.429 -	return NULL;
  31.430 -}
  31.431 -
  31.432 -IPluginContext *CPlugin::GetBaseContext()
  31.433 -{
  31.434 -	if (m_pRuntime == NULL)
  31.435 -	{
  31.436 -		return NULL;
  31.437 -	}
  31.438 -
  31.439 -	return m_pRuntime->GetDefaultContext();
  31.440 -}
  31.441 -
  31.442 -sp_context_t *CPlugin::GetContext()
  31.443 -{
  31.444 -	return NULL;
  31.445 -}
  31.446 -
  31.447 -const char *CPlugin::GetFilename()
  31.448 -{
  31.449 -	return m_filename;
  31.450 -}
  31.451 -
  31.452 -PluginType CPlugin::GetType()
  31.453 -{
  31.454 -	return m_type;
  31.455 -}
  31.456 -
  31.457 -const sm_plugininfo_t *CPlugin::GetPublicInfo()
  31.458 -{
  31.459 -	if (GetStatus() >= Plugin_Created)
  31.460 -	{
  31.461 -		return NULL;
  31.462 -	}
  31.463 -	return &m_info;
  31.464 -}
  31.465 -
  31.466 -unsigned int CPlugin::GetSerial()
  31.467 -{
  31.468 -	return m_serial;
  31.469 -}
  31.470 -
  31.471 -PluginStatus CPlugin::GetStatus()
  31.472 -{
  31.473 -	return m_status;
  31.474 -}
  31.475 -
  31.476 -bool CPlugin::IsDebugging()
  31.477 -{
  31.478 -	if (m_pRuntime == NULL)
  31.479 -	{
  31.480 -		return false;
  31.481 -	}
  31.482 -
  31.483 -	return true;
  31.484 -}
  31.485 -
  31.486 -void CPlugin::LibraryActions(bool dropping)
  31.487 -{
  31.488 -	List<String>::iterator iter;
  31.489 -	for (iter = m_Libraries.begin();
  31.490 -		iter != m_Libraries.end();
  31.491 -		iter++)
  31.492 -	{
  31.493 -		g_PluginSys.OnLibraryAction((*iter).c_str(), true, dropping);
  31.494 -	}
  31.495 -}
  31.496 -
  31.497 -bool CPlugin::SetPauseState(bool paused)
  31.498 -{
  31.499 -	if (paused && GetStatus() != Plugin_Running)
  31.500 -	{
  31.501 -		return false;
  31.502 -	} else if (!paused && GetStatus() != Plugin_Paused) {
  31.503 -		return false;
  31.504 -	}
  31.505 -
  31.506 -	if (paused)
  31.507 -	{
  31.508 -		LibraryActions(true);
  31.509 -	}
  31.510 -
  31.511 -	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginPauseChange");
  31.512 -	if (pFunction)
  31.513 -	{
  31.514 -		cell_t result;
  31.515 -		pFunction->PushCell(paused ? 1 : 0);
  31.516 -		pFunction->Execute(&result);
  31.517 -	}
  31.518 -
  31.519 -	if (paused)
  31.520 -	{
  31.521 -		m_status = Plugin_Paused;
  31.522 -		m_pRuntime->SetPauseState(true);
  31.523 -	} else {
  31.524 -		m_status = Plugin_Running;
  31.525 -		m_pRuntime->SetPauseState(false);
  31.526 -	}
  31.527 -
  31.528 -	g_PluginSys._SetPauseState(this, paused);
  31.529 -
  31.530 -	if (!paused)
  31.531 -	{
  31.532 -		LibraryActions(false);
  31.533 -	}
  31.534 -
  31.535 -	return true;
  31.536 -}
  31.537 -
  31.538 -IdentityToken_t *CPlugin::GetIdentity()
  31.539 -{
  31.540 -	return m_ident;
  31.541 -}
  31.542 -
  31.543 -bool CPlugin::IsRunnable()
  31.544 -{
  31.545 -	return (m_status <= Plugin_Paused) ? true : false;
  31.546 -}
  31.547 -
  31.548 -time_t CPlugin::GetFileTimeStamp()
  31.549 -{
  31.550 -	char path[PLATFORM_MAX_PATH];
  31.551 -	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename);
  31.552 -#ifdef PLATFORM_WINDOWS
  31.553 -	struct _stat s;
  31.554 -	if (_stat(path, &s) != 0)
  31.555 -#elif defined PLATFORM_POSIX
  31.556 -	struct stat s;
  31.557 -	if (stat(path, &s) != 0)
  31.558 -#endif
  31.559 -	{
  31.560 -		return 0;
  31.561 -	}
  31.562 -	else
  31.563 -	{
  31.564 -		return s.st_mtime;
  31.565 -	}
  31.566 -}
  31.567 -
  31.568 -time_t CPlugin::GetTimeStamp()
  31.569 -{
  31.570 -	return m_LastAccess;
  31.571 -}
  31.572 -
  31.573 -void CPlugin::SetTimeStamp(time_t t)
  31.574 -{
  31.575 -	m_LastAccess = t;
  31.576 -}
  31.577 -
  31.578 -IPhraseCollection *CPlugin::GetPhrases()
  31.579 -{
  31.580 -	return m_pPhrases;
  31.581 -}
  31.582 -
  31.583 -void CPlugin::DependencyDropped(CPlugin *pOwner)
  31.584 -{
  31.585 -	if (!m_pRuntime)
  31.586 -	{
  31.587 -		return;
  31.588 -	}
  31.589 -
  31.590 -	List<String>::iterator reqlib_iter;
  31.591 -	List<String>::iterator lib_iter;
  31.592 -	for (lib_iter=pOwner->m_Libraries.begin(); lib_iter!=pOwner->m_Libraries.end(); lib_iter++)
  31.593 -	{
  31.594 -		for (reqlib_iter=m_RequiredLibs.begin(); reqlib_iter!=m_RequiredLibs.end(); reqlib_iter++)
  31.595 -		{
  31.596 -			if ((*reqlib_iter) == (*lib_iter))
  31.597 -			{
  31.598 -				m_LibraryMissing = true;
  31.599 -			}
  31.600 -		}	
  31.601 -	}
  31.602 -
  31.603 -	List<NativeEntry *>::iterator iter;
  31.604 -	NativeEntry *pNative;
  31.605 -	sp_native_t *native;
  31.606 -	uint32_t idx;
  31.607 -	unsigned int unbound = 0;
  31.608 -
  31.609 -	for (iter = pOwner->m_Natives.begin();
  31.610 -		 iter != pOwner->m_Natives.end();
  31.611 -		 iter++)
  31.612 -	{
  31.613 -		pNative = (*iter);
  31.614 -		/* Find this native! */
  31.615 -		if (m_pRuntime->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE)
  31.616 -		{
  31.617 -			continue;
  31.618 -		}
  31.619 -		/* Unbind it */
  31.620 -		m_pRuntime->GetNativeByIndex(idx, &native);
  31.621 -		native->pfn = NULL;
  31.622 -		native->status = SP_NATIVE_UNBOUND;
  31.623 -		unbound++;
  31.624 -	}
  31.625 -
  31.626 -	if (unbound)
  31.627 -	{
  31.628 -		m_FakeNativesMissing = true;
  31.629 -	}
  31.630 -
  31.631 -	/* :IDEA: in the future, add native trapping? */
  31.632 -	if (m_FakeNativesMissing || m_LibraryMissing)
  31.633 -	{
  31.634 -		SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
  31.635 -	}
  31.636 -}
  31.637 -
  31.638 -unsigned int CPlugin::GetConfigCount()
  31.639 -{
  31.640 -	return (unsigned int)m_configs.size();
  31.641 -}
  31.642 -
  31.643 -AutoConfig *CPlugin::GetConfig(unsigned int i)
  31.644 -{
  31.645 -	if (i >= GetConfigCount())
  31.646 -	{
  31.647 -		return NULL;
  31.648 -	}
  31.649 -
  31.650 -	return m_configs[i];
  31.651 -}
  31.652 -
  31.653 -void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder)
  31.654 -{
  31.655 -	/* Do a check for duplicates to prevent double-execution */
  31.656 -	for (size_t i = 0; i < m_configs.size(); i++)
  31.657 -	{
  31.658 -		if (m_configs[i]->autocfg.compare(cfg) == 0
  31.659 -			&& m_configs[i]->folder.compare(folder) == 0
  31.660 -			&& m_configs[i]->create == autoCreate)
  31.661 -		{
  31.662 -			return;
  31.663 -		}
  31.664 -	}
  31.665 -
  31.666 -	AutoConfig *c = new AutoConfig;
  31.667 -
  31.668 -	c->autocfg = cfg;
  31.669 -	c->folder = folder;
  31.670 -	c->create = autoCreate;
  31.671 -
  31.672 -	m_configs.push_back(c);
  31.673 -}
  31.674 -
  31.675 -void CPlugin::DropEverything()
  31.676 -{
  31.677 -	CPlugin *pOther;
  31.678 -	List<CPlugin *>::iterator iter;
  31.679 -	List<WeakNative>::iterator wk_iter;
  31.680 -
  31.681 -	/* Tell everyone that depends on us that we're about to drop */
  31.682 -	for (iter = m_Dependents.begin();
  31.683 -		 iter != m_Dependents.end(); 
  31.684 -		 iter++)
  31.685 -	{
  31.686 -		pOther = (*iter);
  31.687 -		pOther->DependencyDropped(this);
  31.688 -	}
  31.689 -
  31.690 -	/* Note: we don't care about things we depend on. 
  31.691 -	 * The reason is that extensions have their own cleanup 
  31.692 -	 * code for plugins.  Although the "right" design would be 
  31.693 -	 * to centralize that here, i'm omitting it for now.  Thus, 
  31.694 -	 * the code below to walk the plugins list will suffice.
  31.695 -	 */
  31.696 -	
  31.697 -	/* Other plugins could be holding weak references that were 
  31.698 -	 * added by us.  We need to clean all of those up now.
  31.699 -	 */
  31.700 -	for (iter = g_PluginSys.m_plugins.begin();
  31.701 -		 iter != g_PluginSys.m_plugins.end();
  31.702 -		 iter++)
  31.703 -	{
  31.704 -		(*iter)->DropRefsTo(this);
  31.705 -	}
  31.706 -
  31.707 -	/* Proceed with the rest of the necessities. */
  31.708 -	CNativeOwner::DropEverything();
  31.709 -}
  31.710 -
  31.711 -bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
  31.712 -{
  31.713 -	NativeEntry *pEntry;
  31.714 -
  31.715 -	if ((pEntry = g_ShareSys.AddFakeNative(pFunc, name, func)) == NULL)
  31.716 -	{
  31.717 -		return false;
  31.718 -	}
  31.719 -
  31.720 -	m_Natives.push_back(pEntry);
  31.721 -
  31.722 -	return true;
  31.723 -}
  31.724 -
  31.725 -/*******************
  31.726 - * PLUGIN ITERATOR *
  31.727 - *******************/
  31.728 -
  31.729 -CPluginManager::CPluginIterator::CPluginIterator(List<CPlugin *> *_mylist)
  31.730 -{
  31.731 -	mylist = _mylist;
  31.732 -	Reset();
  31.733 -}
  31.734 -
  31.735 -IPlugin *CPluginManager::CPluginIterator::GetPlugin()
  31.736 -{
  31.737 -	return (*current);
  31.738 -}
  31.739 -
  31.740 -bool CPluginManager::CPluginIterator::MorePlugins()
  31.741 -{
  31.742 -	return (current != mylist->end());
  31.743 -}
  31.744 -
  31.745 -void CPluginManager::CPluginIterator::NextPlugin()
  31.746 -{
  31.747 -	current++;
  31.748 -}
  31.749 -
  31.750 -void CPluginManager::CPluginIterator::Release()
  31.751 -{
  31.752 -	g_PluginSys.ReleaseIterator(this);
  31.753 -}
  31.754 -
  31.755 -CPluginManager::CPluginIterator::~CPluginIterator()
  31.756 -{
  31.757 -}
  31.758 -
  31.759 -void CPluginManager::CPluginIterator::Reset()
  31.760 -{
  31.761 -	current = mylist->begin();
  31.762 -}
  31.763 -
  31.764 -/******************
  31.765 - * PLUGIN MANAGER *
  31.766 - ******************/
  31.767 -
  31.768 -CPluginManager::CPluginManager()
  31.769 -{
  31.770 -	m_LoadLookup = sm_trie_create();
  31.771 -	m_AllPluginsLoaded = false;
  31.772 -	m_MyIdent = NULL;
  31.773 -	m_LoadingLocked = false;
  31.774 -}
  31.775 -
  31.776 -CPluginManager::~CPluginManager()
  31.777 -{
  31.778 -	/* :NOTICE: 
  31.779 -	 * Ignore the fact that there might be plugins in the cache.
  31.780 -	 * This usually means that Core is not being unloaded properly, and everything
  31.781 -	 * will crash anyway.  YAY
  31.782 -	 */
  31.783 -	sm_trie_destroy(m_LoadLookup);
  31.784 -
  31.785 -	CStack<CPluginManager::CPluginIterator *>::iterator iter;
  31.786 -	for (iter=m_iters.begin(); iter!=m_iters.end(); iter++)
  31.787 -	{
  31.788 -		delete (*iter);
  31.789 -	}
  31.790 -	m_iters.popall();
  31.791 -}
  31.792 -
  31.793 -void CPluginManager::Shutdown()
  31.794 -{
  31.795 -	List<CPlugin *>::iterator iter;
  31.796 -
  31.797 -	while ((iter = m_plugins.begin()) != m_plugins.end())
  31.798 -	{
  31.799 -		UnloadPlugin(*iter);
  31.800 -	}
  31.801 -}
  31.802 -
  31.803 -void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
  31.804 -{
  31.805 -	/* First read in the database of plugin settings */
  31.806 -	SMCError err;
  31.807 -	SMCStates states;
  31.808 -	m_AllPluginsLoaded = false;
  31.809 -	if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &states)) != SMCError_Okay)
  31.810 -	{
  31.811 -		g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
  31.812 -		const char *err_msg = textparsers->GetSMCErrorString(err);
  31.813 -		if (err_msg)
  31.814 -		{
  31.815 -			g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
  31.816 -		}
  31.817 -	}
  31.818 -
  31.819 -	LoadPluginsFromDir(basedir, NULL);
  31.820 -}
  31.821 -
  31.822 -void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
  31.823 -{
  31.824 -	char base_path[PLATFORM_MAX_PATH];
  31.825 -
  31.826 -	/* Form the current path to start reading from */
  31.827 -	if (localpath == NULL)
  31.828 -	{
  31.829 -		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
  31.830 -	} else {
  31.831 -		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
  31.832 -	}
  31.833 -
  31.834 -	IDirectory *dir = g_LibSys.OpenDirectory(base_path);
  31.835 -
  31.836 -	if (!dir)
  31.837 -	{
  31.838 -		char error[256];
  31.839 -		g_LibSys.GetPlatformError(error, sizeof(error));
  31.840 -		g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
  31.841 -		g_Logger.LogError("[SM] Platform returned error: %s", error);
  31.842 -		return;
  31.843 -	}
  31.844 -
  31.845 -	while (dir->MoreFiles())
  31.846 -	{
  31.847 -		if (dir->IsEntryDirectory() 
  31.848 -			&& (strcmp(dir->GetEntryName(), ".") != 0)
  31.849 -			&& (strcmp(dir->GetEntryName(), "..") != 0)
  31.850 -			&& (strcmp(dir->GetEntryName(), "disabled") != 0)
  31.851 -			&& (strcmp(dir->GetEntryName(), "optional") != 0))
  31.852 -		{
  31.853 -			char new_local[PLATFORM_MAX_PATH];
  31.854 -			if (localpath == NULL)
  31.855 -			{
  31.856 -				/* If no path yet, don't add a former slash */
  31.857 -				snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
  31.858 -			} else {
  31.859 -				g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
  31.860 -			}
  31.861 -			LoadPluginsFromDir(basedir, new_local);
  31.862 -		} else if (dir->IsEntryFile()) {
  31.863 -			const char *name = dir->GetEntryName();
  31.864 -			size_t len = strlen(name);
  31.865 -			if (len >= 4
  31.866 -				&& strcmp(&name[len-4], ".smx") == 0)
  31.867 -			{
  31.868 -				/* If the filename matches, load the plugin */
  31.869 -				char plugin[PLATFORM_MAX_PATH];
  31.870 -				if (localpath == NULL)
  31.871 -				{
  31.872 -					snprintf(plugin, sizeof(plugin), "%s", name);
  31.873 -				} else {
  31.874 -					g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
  31.875 -				}
  31.876 -				LoadAutoPlugin(plugin);
  31.877 -			}
  31.878 -		}
  31.879 -		dir->NextEntry();
  31.880 -	}
  31.881 -	g_LibSys.CloseDirectory(dir);
  31.882 -}
  31.883 -
  31.884 -LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
  31.885 -{
  31.886 -	if (m_LoadingLocked)
  31.887 -	{
  31.888 -		return LoadRes_NeverLoad;
  31.889 -	}
  31.890 -
  31.891 -	int err;
  31.892 -	bool no_load = false;
  31.893 -	PluginSettings *pset;
  31.894 -	unsigned int setcount = m_PluginInfo.GetSettingsNum();
  31.895 -	for (unsigned int i=0; i<setcount; i++)
  31.896 -	{
  31.897 -		if ((pset = m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
  31.898 -		{
  31.899 -			continue;
  31.900 -		}
  31.901 -		if (pset->blockload_val)
  31.902 -		{
  31.903 -			no_load = true;
  31.904 -			break;
  31.905 -		}
  31.906 -	}
  31.907 -
  31.908 -	/**
  31.909 -	 * Does this plugin already exist?
  31.910 -	 */
  31.911 -	CPlugin *pPlugin;
  31.912 -	if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
  31.913 -	{
  31.914 -		/* Check to see if we should try reloading it */
  31.915 -		if (pPlugin->GetStatus() == Plugin_BadLoad
  31.916 -			|| pPlugin->GetStatus() == Plugin_Error
  31.917 -			|| pPlugin->GetStatus() == Plugin_Failed
  31.918 -			|| no_load)
  31.919 -		{
  31.920 -			UnloadPlugin(pPlugin);
  31.921 -		}
  31.922 -		else
  31.923 -		{
  31.924 -			if (_plugin)
  31.925 -			{
  31.926 -				*_plugin = pPlugin;
  31.927 -			}
  31.928 -			return LoadRes_AlreadyLoaded;
  31.929 -		}
  31.930 -	}
  31.931 -
  31.932 -	if (no_load)
  31.933 -	{
  31.934 -		return LoadRes_NeverLoad;
  31.935 -	}
  31.936 -
  31.937 -	pPlugin = CPlugin::CreatePlugin(path, error, maxlength);
  31.938 -
  31.939 -	assert(pPlugin != NULL);
  31.940 -
  31.941 -	pPlugin->m_type = PluginType_MapUpdated;
  31.942 -
  31.943 -	ICompilation *co = NULL;
  31.944 -
  31.945 -	if (pPlugin->m_status == Plugin_Uncompiled)
  31.946 -	{
  31.947 -		co = g_pSourcePawn2->StartCompilation();
  31.948 -	}
  31.949 -
  31.950 -	for (unsigned int i=0; i<setcount; i++)
  31.951 -	{
  31.952 -		if ((pset=m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
  31.953 -		{
  31.954 -			continue;
  31.955 -		}
  31.956 -		pPlugin->m_type = pset->type_val;
  31.957 -		if (co)
  31.958 -		{
  31.959 -			for (unsigned int j=0; j<pset->opts_num; j++)
  31.960 -			{
  31.961 -				const char *key, *val;
  31.962 -				m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
  31.963 -				if (!key || !val)
  31.964 -				{
  31.965 -					continue;
  31.966 -				}
  31.967 -				if ((err = co->SetOption(key, val)) == SP_ERROR_NONE)
  31.968 -				{
  31.969 -					if (error)
  31.970 -					{
  31.971 -						snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
  31.972 -					}
  31.973 -					co->Abort();
  31.974 -					co = NULL;
  31.975 -					break;
  31.976 -				}
  31.977 -			}
  31.978 -		}
  31.979 -	}
  31.980 -
  31.981 -	/* Do the actual compiling */
  31.982 -	if (co != NULL)
  31.983 -	{
  31.984 -		char fullpath[PLATFORM_MAX_PATH];
  31.985 -		g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", pPlugin->m_filename);
  31.986 -
  31.987 -		pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(co, fullpath, &err);
  31.988 -		if (pPlugin->m_pRuntime == NULL)
  31.989 -		{
  31.990 -			snprintf(error, 
  31.991 -				maxlength, 
  31.992 -				"Unable to load plugin (error %d: %s)", 
  31.993 -				err, 
  31.994 -				g_pSourcePawn2->GetErrorString(err));
  31.995 -			pPlugin->m_status = Plugin_BadLoad;
  31.996 -		}
  31.997 -		else
  31.998 -		{
  31.999 -			if (pPlugin->UpdateInfo())
 31.1000 -			{
 31.1001 -				pPlugin->m_status = Plugin_Created;
 31.1002 -			}
 31.1003 -			else
 31.1004 -			{
 31.1005 -				UTIL_Format(error, maxlength, "%s", pPlugin->m_errormsg);
 31.1006 -			}
 31.1007 -		}
 31.1008 -	}
 31.1009 -
 31.1010 -	/* Get the status */
 31.1011 -	if (pPlugin->GetStatus() == Plugin_Created)
 31.1012 -	{
 31.1013 -		/* First native pass - add anything from Core */
 31.1014 -		g_ShareSys.BindNativesToPlugin(pPlugin, true);
 31.1015 -		pPlugin->InitIdentity();
 31.1016 -		if (pPlugin->Call_AskPluginLoad(error, maxlength))
 31.1017 -		{
 31.1018 -			/* Autoload any modules */
 31.1019 -			LoadOrRequireExtensions(pPlugin, 1, error, maxlength);
 31.1020 -		}
 31.1021 -		else
 31.1022 -		{
 31.1023 -			pPlugin->SetErrorState(Plugin_Failed, "%s", error);
 31.1024 -		}
 31.1025 -	}
 31.1026 -
 31.1027 -	/* Save the time stamp */
 31.1028 -	time_t t = pPlugin->GetFileTimeStamp();
 31.1029 -	pPlugin->SetTimeStamp(t);
 31.1030 -
 31.1031 -	if (_plugin)
 31.1032 -	{
 31.1033 -		*_plugin = pPlugin;
 31.1034 -	}
 31.1035 -
 31.1036 -	return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure;
 31.1037 -}
 31.1038 -
 31.1039 -IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded)
 31.1040 -{
 31.1041 -	CPlugin *pl;
 31.1042 -	LoadRes res;
 31.1043 -
 31.1044 -	*wasloaded = false;
 31.1045 -	if ((res=_LoadPlugin(&pl, path, true, type, error, maxlength)) == LoadRes_Failure)
 31.1046 -	{
 31.1047 -		delete pl;
 31.1048 -		return NULL;
 31.1049 -	}
 31.1050 -
 31.1051 -	if (res == LoadRes_AlreadyLoaded)
 31.1052 -	{
 31.1053 -		*wasloaded = true;
 31.1054 -		return pl;
 31.1055 -	}
 31.1056 -
 31.1057 -	if (res == LoadRes_NeverLoad)
 31.1058 -	{
 31.1059 -		if (m_LoadingLocked)
 31.1060 -		{
 31.1061 -			UTIL_Format(error, maxlength, "There is a global plugin loading lock in effect");
 31.1062 -		}
 31.1063 -		else
 31.1064 -		{
 31.1065 -			UTIL_Format(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
 31.1066 -		}
 31.1067 -		return NULL;
 31.1068 -	}
 31.1069 -
 31.1070 -	AddPlugin(pl);
 31.1071 -
 31.1072 -	/* Run second pass if we need to */
 31.1073 -	if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
 31.1074 -	{
 31.1075 -		if (!RunSecondPass(pl, error, maxlength))
 31.1076 -		{
 31.1077 -			UnloadPlugin(pl);
 31.1078 -			return NULL;
 31.1079 -		}
 31.1080 -		pl->Call_OnAllPluginsLoaded();
 31.1081 -	}
 31.1082 -
 31.1083 -	return pl;
 31.1084 -}
 31.1085 -
 31.1086 -void CPluginManager::LoadAutoPlugin(const char *plugin)
 31.1087 -{
 31.1088 -	CPlugin *pl = NULL;
 31.1089 -	LoadRes res;
 31.1090 -	char error[255] = "Unknown error";
 31.1091 -
 31.1092 -	if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
 31.1093 -	{
 31.1094 -		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
 31.1095 -		pl->SetErrorState(
 31.1096 -			pl->GetStatus() == Plugin_BadLoad ? Plugin_BadLoad : Plugin_Failed, 
 31.1097 -			"%s",
 31.1098 -			error);
 31.1099 -	}
 31.1100 -
 31.1101 -	if (res == LoadRes_Successful || res == LoadRes_Failure)
 31.1102 -	{
 31.1103 -		AddPlugin(pl);
 31.1104 -	}
 31.1105 -}
 31.1106 -
 31.1107 -void CPluginManager::AddPlugin(CPlugin *pPlugin)
 31.1108 -{
 31.1109 -	List<IPluginsListener *>::iterator iter;
 31.1110 -	IPluginsListener *pListener;
 31.1111 -
 31.1112 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 31.1113 -	{
 31.1114 -		pListener = (*iter);
 31.1115 -		pListener->OnPluginCreated(pPlugin);
 31.1116 -	}
 31.1117 -
 31.1118 -	m_plugins.push_back(pPlugin);
 31.1119 -	sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
 31.1120 -}
 31.1121 -
 31.1122 -void CPluginManager::LoadAll_SecondPass()
 31.1123 -{
 31.1124 -	List<CPlugin *>::iterator iter;
 31.1125 -	CPlugin *pPlugin;
 31.1126 -
 31.1127 -	char error[256];
 31.1128 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 31.1129 -	{
 31.1130 -		pPlugin = (*iter);
 31.1131 -		if (pPlugin->GetStatus() == Plugin_Loaded)
 31.1132 -		{
 31.1133 -			error[0] = '\0';
 31.1134 -			if (!RunSecondPass(pPlugin, error, sizeof(error)))
 31.1135 -			{
 31.1136 -				g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
 31.1137 -				pPlugin->SetErrorState(Plugin_Failed, "%s", error);
 31.1138 -			}
 31.1139 -		}
 31.1140 -	}
 31.1141 -
 31.1142 -	m_AllPluginsLoaded = true;
 31.1143 -}
 31.1144 -
 31.1145 -bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength)
 31.1146 -{
 31.1147 -	struct _pl
 31.1148 -	{
 31.1149 -		cell_t name;
 31.1150 -		cell_t file;
 31.1151 -		cell_t required;
 31.1152 -	} *pl;
 31.1153 -
 31.1154 -	IPluginContext *pBase = pPlugin->GetBaseContext();
 31.1155 -	uint32_t num = pBase->GetPubVarsNum();
 31.1156 -	sp_pubvar_t *pubvar;
 31.1157 -	char *name, *file;
 31.1158 -	char pathfile[PLATFORM_MAX_PATH];
 31.1159 -
 31.1160 -	for (uint32_t i=0; i<num; i++)
 31.1161 -	{
 31.1162 -		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 31.1163 -		{
 31.1164 -			continue;
 31.1165 -		}
 31.1166 -		if (strncmp(pubvar->name, "__pl_", 5) == 0)
 31.1167 -		{
 31.1168 -			pl = (_pl *)pubvar->offs;
 31.1169 -			if (pBase->LocalToString(pl->file, &file) != SP_ERROR_NONE)
 31.1170 -			{
 31.1171 -				continue;
 31.1172 -			}
 31.1173 -			if (pBase->LocalToString(pl->name, &name) != SP_ERROR_NONE)
 31.1174 -			{
 31.1175 -				continue;
 31.1176 -			}
 31.1177 -			g_LibSys.GetFileFromPath(pathfile, sizeof(pathfile), pPlugin->GetFilename());
 31.1178 -			if (strcmp(pathfile, file) == 0)
 31.1179 -			{
 31.1180 -				continue;
 31.1181 -			}
 31.1182 -			if (pl->required == false)
 31.1183 -			{
 31.1184 -				IPluginFunction *pFunc;
 31.1185 -				char buffer[64];
 31.1186 -				UTIL_Format(buffer, sizeof(buffer), "__pl_%s_SetNTVOptional", &pubvar->name[5]);
 31.1187 -				if ((pFunc=pBase->GetFunctionByName(buffer)))
 31.1188 -				{
 31.1189 -					cell_t res;
 31.1190 -					pFunc->Execute(&res);
 31.1191 -					if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
 31.1192 -					{
 31.1193 -						if (error)
 31.1194 -						{
 31.1195 -							snprintf(error, maxlength, "Fatal error during initializing plugin load");
 31.1196 -						}
 31.1197 -						return false;
 31.1198 -					}
 31.1199 -				}
 31.1200 -			}
 31.1201 -			else
 31.1202 -			{
 31.1203 -				/* Check that we aren't registering the same library twice */
 31.1204 -				if (pPlugin->m_RequiredLibs.find(name) == pPlugin->m_RequiredLibs.end())
 31.1205 -				{
 31.1206 -					pPlugin->m_RequiredLibs.push_back(name);
 31.1207 -				}
 31.1208 -				else
 31.1209 -				{
 31.1210 -					continue;
 31.1211 -				}
 31.1212 -				List<CPlugin *>::iterator iter;
 31.1213 -				CPlugin *pl;
 31.1214 -				bool found = false;
 31.1215 -				for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 31.1216 -				{
 31.1217 -					pl = (*iter);
 31.1218 -					if (pl->m_Libraries.find(name) != pl->m_Libraries.end())
 31.1219 -					{
 31.1220 -						found = true;
 31.1221 -						break;
 31.1222 -					}
 31.1223 -				}
 31.1224 -				if (!found)
 31.1225 -				{
 31.1226 -					if (error)
 31.1227 -					{
 31.1228 -						snprintf(error, maxlength, "Could not find required plugin \"%s\"", name);
 31.1229 -					}
 31.1230 -					return false;
 31.1231 -				}
 31.1232 -			}
 31.1233 -		}
 31.1234 -	}
 31.1235 -
 31.1236 -	return true;
 31.1237 -}
 31.1238 -
 31.1239 -bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
 31.1240 -{
 31.1241 -	/* Find any extensions this plugin needs */
 31.1242 -	struct _ext
 31.1243 -	{
 31.1244 -		cell_t name;
 31.1245 -		cell_t file;
 31.1246 -		cell_t autoload;
 31.1247 -		cell_t required;
 31.1248 -	} *ext;
 31.1249 -
 31.1250 -	IPluginContext *pBase = pPlugin->GetBaseContext();
 31.1251 -	uint32_t num = pBase->GetPubVarsNum();
 31.1252 -	sp_pubvar_t *pubvar;
 31.1253 -	IExtension *pExt;
 31.1254 -	char path[PLATFORM_MAX_PATH];
 31.1255 -	char *file, *name;
 31.1256 -	for (uint32_t i=0; i<num; i++)
 31.1257 -	{
 31.1258 -		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 31.1259 -		{
 31.1260 -			continue;
 31.1261 -		}
 31.1262 -		if (strncmp(pubvar->name, "__ext_", 6) == 0)
 31.1263 -		{
 31.1264 -			ext = (_ext *)pubvar->offs;
 31.1265 -			if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
 31.1266 -			{
 31.1267 -				continue;
 31.1268 -			}
 31.1269 -			if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
 31.1270 -			{
 31.1271 -				continue;
 31.1272 -			}
 31.1273 -			if (pass == 1)
 31.1274 -			{
 31.1275 -				/* Attempt to auto-load if necessary */
 31.1276 -				if (ext->autoload)
 31.1277 -				{
 31.1278 -					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
 31.1279 -					g_Extensions.LoadAutoExtension(path);
 31.1280 -				}
 31.1281 -			}
 31.1282 -			else if (pass == 2)
 31.1283 -			{
 31.1284 -				/* Is this required? */
 31.1285 -				if (ext->required)
 31.1286 -				{
 31.1287 -					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
 31.1288 -					if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
 31.1289 -					{
 31.1290 -						pExt = g_Extensions.FindExtensionByName(name);
 31.1291 -					}
 31.1292 -					/* :TODO: should we bind to unloaded extensions?
 31.1293 -					 * Currently the extension manager will ignore this.
 31.1294 -					 */
 31.1295 -					if (!pExt || !pExt->IsRunning(NULL, 0))
 31.1296 -					{
 31.1297 -						if (error)
 31.1298 -						{
 31.1299 -							snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
 31.1300 -						}
 31.1301 -						return false;
 31.1302 -					}
 31.1303 -					else
 31.1304 -					{
 31.1305 -						g_Extensions.BindChildPlugin(pExt, pPlugin);
 31.1306 -					}
 31.1307 -				}
 31.1308 -				else
 31.1309 -				{
 31.1310 -					IPluginFunction *pFunc;
 31.1311 -					char buffer[64];
 31.1312 -					UTIL_Format(buffer, sizeof(buffer), "__ext_%s_SetNTVOptional", &pubvar->name[6]);
 31.1313 -
 31.1314 -					if ((pFunc = pBase->GetFunctionByName(buffer)) != NULL)
 31.1315 -					{
 31.1316 -						cell_t res;
 31.1317 -						pFunc->Execute(&res);
 31.1318 -						if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
 31.1319 -						{
 31.1320 -							if (error)
 31.1321 -							{
 31.1322 -								UTIL_Format(error, maxlength, "Fatal error during plugin initialization (ext req)");
 31.1323 -							}
 31.1324 -							return false;
 31.1325 -						}
 31.1326 -					}
 31.1327 -				}
 31.1328 -			}
 31.1329 -		}
 31.1330 -	}
 31.1331 -
 31.1332 -	return true;
 31.1333 -}
 31.1334 -
 31.1335 -bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
 31.1336 -{
 31.1337 -	/* Second pass for extension requirements */
 31.1338 -	if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
 31.1339 -	{
 31.1340 -		return false;
 31.1341 -	}
 31.1342 -
 31.1343 -	if (!FindOrRequirePluginDeps(pPlugin, error, maxlength))
 31.1344 -	{
 31.1345 -		return false;
 31.1346 -	}
 31.1347 -
 31.1348 -	/* Run another binding pass */
 31.1349 -	g_ShareSys.BindNativesToPlugin(pPlugin, false);
 31.1350 -
 31.1351 -	/* Find any unbound natives. Right now, these are not allowed. */
 31.1352 -	IPluginContext *pContext = pPlugin->GetBaseContext();
 31.1353 -	uint32_t num = pContext->GetNativesNum();
 31.1354 -	sp_native_t *native;
 31.1355 -	for (unsigned int i=0; i<num; i++)
 31.1356 -	{
 31.1357 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
 31.1358 -		{
 31.1359 -			break;
 31.1360 -		}
 31.1361 -		if (native->status == SP_NATIVE_UNBOUND
 31.1362 -			&& native->name[0] != '@'
 31.1363 -			&& !(native->flags & SP_NTVFLAG_OPTIONAL))
 31.1364 -		{
 31.1365 -			if (error)
 31.1366 -			{
 31.1367 -				snprintf(error, maxlength, "Native \"%s\" was not found", native->name);
 31.1368 -			}
 31.1369 -			return false;
 31.1370 -		}
 31.1371 -	}
 31.1372 -
 31.1373 -	/* Finish by telling all listeners */
 31.1374 -	List<IPluginsListener *>::iterator iter;
 31.1375 -	IPluginsListener *pListener;
 31.1376 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 31.1377 -	{
 31.1378 -		pListener = (*iter);
 31.1379 -		pListener->OnPluginLoaded(pPlugin);
 31.1380 -	}
 31.1381 -	
 31.1382 -	/* Tell this plugin to finish initializing itself */
 31.1383 -	pPlugin->Call_OnPluginStart();
 31.1384 -
 31.1385 -	/* Now, if we have fake natives, go through all plugins that might need rebinding */
 31.1386 -	if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_Natives.size())
 31.1387 -	{
 31.1388 -		List<CPlugin *>::iterator pl_iter;
 31.1389 -		CPlugin *pOther;
 31.1390 -		for (pl_iter = m_plugins.begin();
 31.1391 -			 pl_iter != m_plugins.end();
 31.1392 -			 pl_iter++)
 31.1393 -		{
 31.1394 -			pOther = (*pl_iter);
 31.1395 -			if ((pOther->GetStatus() == Plugin_Error
 31.1396 -				&& (pOther->m_FakeNativesMissing || pOther->m_LibraryMissing))
 31.1397 -				|| pOther->m_FakeNativesMissing)
 31.1398 -			{
 31.1399 -				TryRefreshDependencies(pOther);
 31.1400 -			}
 31.1401 -			else if ((pOther->GetStatus() == Plugin_Running
 31.1402 -					  || pOther->GetStatus() == Plugin_Paused)
 31.1403 -					 && pOther != pPlugin)
 31.1404 -			{
 31.1405 -				List<NativeEntry *>::iterator nv_iter;
 31.1406 -				for (nv_iter = pPlugin->m_Natives.begin();
 31.1407 -					 nv_iter != pPlugin->m_Natives.end();
 31.1408 -					 nv_iter++)
 31.1409 -				{
 31.1410 -					g_ShareSys.BindNativeToPlugin(pOther, (*nv_iter));
 31.1411 -				}
 31.1412 -			}
 31.1413 -		}
 31.1414 -	}
 31.1415 -
 31.1416 -	/* Go through our libraries and tell other plugins they're added */
 31.1417 -	List<String>::iterator s_iter;
 31.1418 -	for (s_iter = pPlugin->m_Libraries.begin();
 31.1419 -		s_iter != pPlugin->m_Libraries.end();
 31.1420 -		s_iter++)
 31.1421 -	{
 31.1422 -		OnLibraryAction((*s_iter).c_str(), true, false);
 31.1423 -	}
 31.1424 -
 31.1425 -	/* :TODO: optimize? does this even matter? */
 31.1426 -	pPlugin->GetPhrases()->AddPhraseFile("core.phrases");
 31.1427 -
 31.1428 -	return true;
 31.1429 -}
 31.1430 -
 31.1431 -void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
 31.1432 -{
 31.1433 -	assert(pPlugin->GetBaseContext() != NULL);
 31.1434 -
 31.1435 -	g_ShareSys.BindNativesToPlugin(pPlugin, false);
 31.1436 -
 31.1437 -	List<String>::iterator lib_iter;
 31.1438 -	List<String>::iterator req_iter;
 31.1439 -	List<CPlugin *>::iterator pl_iter;
 31.1440 -	CPlugin *pl;
 31.1441 -	for (req_iter=pPlugin->m_RequiredLibs.begin(); req_iter!=pPlugin->m_RequiredLibs.end(); req_iter++)
 31.1442 -	{
 31.1443 -		bool found = false;
 31.1444 -		for (pl_iter=m_plugins.begin(); pl_iter!=m_plugins.end(); pl_iter++)
 31.1445 -		{
 31.1446 -			pl = (*pl_iter);
 31.1447 -			for (lib_iter=pl->m_Libraries.begin(); lib_iter!=pl->m_Libraries.end(); lib_iter++)
 31.1448 -			{
 31.1449 -				if ((*req_iter) == (*lib_iter))
 31.1450 -				{
 31.1451 -					found = true;
 31.1452 -				}
 31.1453 -			}
 31.1454 -		}
 31.1455 -		if (!found)
 31.1456 -		{
 31.1457 -			pPlugin->SetErrorState(Plugin_Error, "Library not found: %s", (*req_iter).c_str());
 31.1458 -			return;
 31.1459 -		}
 31.1460 -	}
 31.1461 -
 31.1462 -	/* Find any unbound natives
 31.1463 -	 * Right now, these are not allowed
 31.1464 -	 */
 31.1465 -	IPluginContext *pContext = pPlugin->GetBaseContext();
 31.1466 -	uint32_t num = pContext->GetNativesNum();
 31.1467 -	sp_native_t *native;
 31.1468 -	for (unsigned int i=0; i<num; i++)
 31.1469 -	{
 31.1470 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
 31.1471 -		{
 31.1472 -			break;
 31.1473 -		}
 31.1474 -		if (native->status == SP_NATIVE_UNBOUND && !(native->flags & SP_NTVFLAG_OPTIONAL))
 31.1475 -		{
 31.1476 -			pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
 31.1477 -			return;
 31.1478 -		}
 31.1479 -	}
 31.1480 -
 31.1481 -	if (pPlugin->GetStatus() == Plugin_Error)
 31.1482 -	{
 31.1483 -		/* If we got here, all natives are okay again! */
 31.1484 -		pPlugin->m_status = Plugin_Running;
 31.1485 -		if (pPlugin->m_pRuntime->IsPaused())
 31.1486 -		{
 31.1487 -			pPlugin->m_pRuntime->SetPauseState(false);
 31.1488 -			_SetPauseState(pPlugin, false);
 31.1489 -		}
 31.1490 -	}
 31.1491 -}
 31.1492 -
 31.1493 -bool CPluginManager::UnloadPlugin(IPlugin *plugin)
 31.1494 -{
 31.1495 -	CPlugin *pPlugin = (CPlugin *)plugin;
 31.1496 -
 31.1497 -	/* This prevents removal during insertion or anything else weird */
 31.1498 -	if (m_plugins.find(pPlugin) == m_plugins.end())
 31.1499 -	{
 31.1500 -		return false;
 31.1501 -	}
 31.1502 -
 31.1503 -	IPluginContext *pContext = plugin->GetBaseContext();
 31.1504 -	if (pContext != NULL && pContext->IsInExec())
 31.1505 -	{
 31.1506 -		char buffer[255];
 31.1507 -		UTIL_Format(buffer, sizeof(buffer), "sm plugins unload %s\n", plugin->GetFilename());
 31.1508 -		engine->ServerCommand(buffer);
 31.1509 -		return false;
 31.1510 -	}
 31.1511 -
 31.1512 -	/* Remove us from the lookup table and linked list */
 31.1513 -	m_plugins.remove(pPlugin);
 31.1514 -	sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
 31.1515 -
 31.1516 -	/* Go through our libraries and tell other plugins they're gone */
 31.1517 -	List<String>::iterator s_iter;
 31.1518 -	for (s_iter = pPlugin->m_Libraries.begin();
 31.1519 -		 s_iter != pPlugin->m_Libraries.end();
 31.1520 -		 s_iter++)
 31.1521 -	{
 31.1522 -		OnLibraryAction((*s_iter).c_str(), true, true);
 31.1523 -	}
 31.1524 -
 31.1525 -	List<IPluginsListener *>::iterator iter;
 31.1526 -	IPluginsListener *pListener;
 31.1527 -
 31.1528 -	if (pPlugin->GetStatus() <= Plugin_Error)
 31.1529 -	{
 31.1530 -		/* Notify listeners of unloading */
 31.1531 -		for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 31.1532 -		{
 31.1533 -			pListener = (*iter);
 31.1534 -			pListener->OnPluginUnloaded(pPlugin);
 31.1535 -		}
 31.1536 -		/* Notify plugin */
 31.1537 -		pPlugin->Call_OnPluginEnd();
 31.1538 -	}
 31.1539 -
 31.1540 -	pPlugin->DropEverything();
 31.1541 -
 31.1542 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 31.1543 -	{
 31.1544 -		/* Notify listeners of destruction */
 31.1545 -		pListener = (*iter);
 31.1546 -		pListener->OnPluginDestroyed(pPlugin);
 31.1547 -	}
 31.1548 -	
 31.1549 -	/* Tell the plugin to delete itself */
 31.1550 -	delete pPlugin;
 31.1551 -
 31.1552 -	return true;
 31.1553 -}
 31.1554 -
 31.1555 -IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
 31.1556 -{
 31.1557 -	IPlugin *pPlugin;
 31.1558 -	IPluginContext *pContext;
 31.1559 -
 31.1560 -	pContext = reinterpret_cast<IPluginContext *>(const_cast<sp_context_t *>(ctx));
 31.1561 -
 31.1562 -	if (pContext->GetKey(2, (void **)&pPlugin))
 31.1563 -	{
 31.1564 -		return pPlugin;
 31.1565 -	}
 31.1566 -
 31.1567 -	return NULL;
 31.1568 -}
 31.1569 -
 31.1570 -CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
 31.1571 -{
 31.1572 -	return (CPlugin *)FindPluginByContext(ctx);
 31.1573 -}
 31.1574 -
 31.1575 -unsigned int CPluginManager::GetPluginCount()
 31.1576 -{
 31.1577 -	return m_plugins.size();
 31.1578 -}
 31.1579 -
 31.1580 -void CPluginManager::AddPluginsListener(IPluginsListener *listener)
 31.1581 -{
 31.1582 -	m_listeners.push_back(listener);
 31.1583 -}
 31.1584 -
 31.1585 -void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
 31.1586 -{
 31.1587 -	m_listeners.remove(listener);
 31.1588 -}
 31.1589 -
 31.1590 -IPluginIterator *CPluginManager::GetPluginIterator()
 31.1591 -{
 31.1592 -	if (m_iters.empty())
 31.1593 -	{
 31.1594 -		return new CPluginIterator(&m_plugins);
 31.1595 -	} else {
 31.1596 -		CPluginIterator *iter = m_iters.front();
 31.1597 -		m_iters.pop();
 31.1598 -		iter->Reset();
 31.1599 -		return iter;
 31.1600 -	}
 31.1601 -}
 31.1602 -
 31.1603 -void CPluginManager::ReleaseIterator(CPluginIterator *iter)
 31.1604 -{
 31.1605 -	m_iters.push(iter);
 31.1606 -}
 31.1607 -
 31.1608 -bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
 31.1609 -{
 31.1610 -	/* As an optimization, we do not call strlen, but compute the length in the first pass */
 31.1611 -	size_t alias_len = 0;
 31.1612 -	size_t local_len = 0;
 31.1613 -
 31.1614 -	const char *ptr = alias;
 31.1615 -	unsigned int alias_explicit_paths = 0;
 31.1616 -	unsigned int alias_path_end = 0;
 31.1617 -	while (*ptr != '\0')
 31.1618 -	{
 31.1619 -		if (*ptr == '\\' || *ptr == '/')
 31.1620 -		{
 31.1621 -			alias_explicit_paths++;
 31.1622 -			alias_path_end = alias_len;
 31.1623 -		}
 31.1624 -		alias_len++;
 31.1625 -		ptr++;
 31.1626 -	}
 31.1627 -
 31.1628 -	if (alias_explicit_paths && alias_path_end == alias_len - 1)
 31.1629 -	{
 31.1630 -		/* Trailing slash is totally invalid here */
 31.1631 -		return false;
 31.1632 -	}
 31.1633 -
 31.1634 -	ptr = localpath;
 31.1635 -	unsigned int local_explicit_paths = 0;
 31.1636 -	unsigned int local_path_end = 0;
 31.1637 -	while (*ptr != '\0')
 31.1638 -	{
 31.1639 -		if (*ptr == '\\' || *ptr == '/')
 31.1640 -		{
 31.1641 -			local_explicit_paths++;
 31.1642 -			local_path_end = local_len;
 31.1643 -		}
 31.1644 -		local_len++;
 31.1645 -		ptr++;
 31.1646 -	}
 31.1647 -
 31.1648 -	/* If the alias has more explicit paths than the real path,
 31.1649 -	 * no match will be possible.
 31.1650 -	 */
 31.1651 -	if (alias_explicit_paths > local_explicit_paths)
 31.1652 -	{
 31.1653 -		return false;
 31.1654 -	}
 31.1655 -
 31.1656 -	if (alias_explicit_paths)
 31.1657 -	{
 31.1658 -		/* We need to find if the paths match now.  For example, these should all match:
 31.1659 -		 * csdm     csdm
 31.1660 -		 * csdm     optional/csdm
 31.1661 -		 * csdm/ban optional/crab/csdm/ban
 31.1662 -		*/
 31.1663 -		const char *aliasptr = alias;
 31.1664 -		const char *localptr = localpath;
 31.1665 -		bool match = true;
 31.1666 -		do
 31.1667 -		{
 31.1668 -			if (*aliasptr != *localptr)
 31.1669 -			{
 31.1670 -				/* We have to knock one path off */
 31.1671 -				local_explicit_paths--;
 31.1672 -				if (alias_explicit_paths > local_explicit_paths)
 31.1673 -				{
 31.1674 -					/* Skip out if we're gonna have an impossible match */
 31.1675 -					return false;
 31.1676 -				}
 31.1677 -				/* Eat up localptr tokens until we get a result */
 31.1678 -				while (((localptr - localpath) < (int)local_path_end)
 31.1679 -					&& *localptr != '/'
 31.1680 -					&& *localptr != '\\')
 31.1681 -				{
 31.1682 -					localptr++;
 31.1683 -				}
 31.1684 -				/* Check if we hit the end of our searchable area.
 31.1685 -				 * This probably isn't possible because of the path 
 31.1686 -				 * count check, but it's a good idea anyway.
 31.1687 -				 */
 31.1688 -				if ((localptr - localpath) >= (int)local_path_end)
 31.1689 -				{
 31.1690 -					return false;
 31.1691 -				} else {
 31.1692 -					/* Consume the slash token */
 31.1693 -					localptr++;
 31.1694 -				}
 31.1695 -				/* Reset the alias pointer so we can continue consuming */
 31.1696 -				aliasptr = alias;
 31.1697 -				match = false;
 31.1698 -				continue;
 31.1699 -			}
 31.1700 -			/* Note:
 31.1701 -			 * This is safe because if localptr terminates early, aliasptr will too
 31.1702 -			 */
 31.1703 -			do
 31.1704 -			{
 31.1705 -				/* We should never reach the end of the string because of this check. */
 31.1706 -				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
 31.1707 -				bool localend = (localptr - localpath) > (int)local_path_end;
 31.1708 -				if (aliasend || localend)
 31.1709 -				{
 31.1710 -					if (aliasend && localend)
 31.1711 -					{
 31.1712 -						/* we matched, and we can break out now */
 31.1713 -						match = true;
 31.1714 -						break;
 31.1715 -					}
 31.1716 -					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
 31.1717 -					match = false;
 31.1718 -					break;
 31.1719 -				}
 31.1720 -
 31.1721 -				/* If we got here, it's safe to compare the next two tokens */
 31.1722 -				if (*localptr != *aliasptr)
 31.1723 -				{
 31.1724 -					match = false;
 31.1725 -					break;
 31.1726 -				}
 31.1727 -				localptr++;
 31.1728 -				aliasptr++;
 31.1729 -			} while (true);
 31.1730 -		} while (!match);
 31.1731 -	}
 31.1732 -
 31.1733 -	/* If we got here, it's time to compare filenames */
 31.1734 -	const char *aliasptr = alias;
 31.1735 -	const char *localptr = localpath;
 31.1736 -
 31.1737 -	if (alias_explicit_paths)
 31.1738 -	{
 31.1739 -		aliasptr = &alias[alias_path_end + 1];
 31.1740 -	}
 31.1741 -
 31.1742 -	if (local_explicit_paths)
 31.1743 -	{
 31.1744 -		localptr = &localpath[local_path_end + 1];
 31.1745 -	}
 31.1746 -
 31.1747 -	while (true)
 31.1748 -	{
 31.1749 -		if (*aliasptr == '*')
 31.1750 -		{
 31.1751 -			/* First, see if this is the last character */
 31.1752 -			if ((unsigned)(aliasptr - alias) == alias_len - 1)
 31.1753 -			{
 31.1754 -				/* If so, there's no need to match anything else */
 31.1755 -				return true;
 31.1756 -			}
 31.1757 -			/* Otherwise, we need to search for an appropriate matching sequence in local.
 31.1758 -			 * Note that we only need to search up to the next asterisk.
 31.1759 -			 */
 31.1760 -			aliasptr++;
 31.1761 -			bool match = true;
 31.1762 -			const char *local_orig = localptr;
 31.1763 -			do
 31.1764 -			{
 31.1765 -				match = true;
 31.1766 -				while (*aliasptr != '\0' && *aliasptr != '*')
 31.1767 -				{
 31.1768 -					/* Since aliasptr is never '\0', localptr hitting the end will fail */
 31.1769 -					if (*aliasptr != *localptr)
 31.1770 -					{
 31.1771 -						match = false;
 31.1772 -						break;
 31.1773 -					}
 31.1774 -					aliasptr++;
 31.1775 -					localptr++;
 31.1776 -				}
 31.1777 -				if (!match)
 31.1778 -				{
 31.1779 -					/* If we didn't get a match, we need to advance the search stream.
 31.1780 -					 * This will let us skip tokens while still searching for another match.
 31.1781 -					 */
 31.1782 -					localptr = ++local_orig;
 31.1783 -					/* Make sure we don't go out of bounds */
 31.1784 -					if (*localptr == '\0')
 31.1785 -					{
 31.1786 -						break;
 31.1787 -					}
 31.1788 -				}
 31.1789 -			} while (!match);
 31.1790 -
 31.1791 -			if (!match)
 31.1792 -			{
 31.1793 -				return false;
 31.1794 -			} else {
 31.1795 -				/* If we got a match, move on to the next token */
 31.1796 -				continue;
 31.1797 -			}
 31.1798 -		} else if (*aliasptr == '\0') {
 31.1799 -			if (*localptr == '\0'
 31.1800 -				||
 31.1801 -				strcmp(localptr, ".smx") == 0)
 31.1802 -			{
 31.1803 -				return true;
 31.1804 -			} else {
 31.1805 -				return false;
 31.1806 -			}
 31.1807 -		} else if (*aliasptr != *localptr) {
 31.1808 -			return false;
 31.1809 -		}
 31.1810 -		aliasptr++;
 31.1811 -		localptr++;
 31.1812 -	}
 31.1813 -
 31.1814 -	return true;
 31.1815 -}
 31.1816 -
 31.1817 -bool CPluginManager::IsLateLoadTime() const
 31.1818 -{
 31.1819 -	return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
 31.1820 -}
 31.1821 -
 31.1822 -void CPluginManager::OnSourceModAllInitialized()
 31.1823 -{
 31.1824 -	m_MyIdent = g_ShareSys.CreateCoreIdentity();
 31.1825 -
 31.1826 -	HandleAccess sec;
 31.1827 -	g_HandleSys.InitAccessDefaults(NULL, &sec);
 31.1828 -
 31.1829 -	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
 31.1830 -	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
 31.1831 -
 31.1832 -	g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
 31.1833 -	g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
 31.1834 -
 31.1835 -	g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
 31.1836 -
 31.1837 -	g_ShareSys.AddInterface(NULL, this);
 31.1838 -}
 31.1839 -
 31.1840 -void CPluginManager::OnSourceModShutdown()
 31.1841 -{
 31.1842 -	g_RootMenu.RemoveRootConsoleCommand("plugins", this);
 31.1843 -
 31.1844 -	UnloadAll();
 31.1845 -
 31.1846 -	g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
 31.1847 -	g_ShareSys.DestroyIdentType(g_PluginIdent);
 31.1848 -	g_ShareSys.DestroyIdentity(m_MyIdent);
 31.1849 -}
 31.1850 -
 31.1851 -void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
 31.1852 -{
 31.1853 -	/* We don't care about the internal object, actually */
 31.1854 -}
 31.1855 -
 31.1856 -bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
 31.1857 -{
 31.1858 -	*pSize = ((CPlugin *)object)->CalcMemUsage();
 31.1859 -	return true;
 31.1860 -}
 31.1861 -
 31.1862 -IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
 31.1863 -{
 31.1864 -	IPlugin *pPlugin;
 31.1865 -	HandleError _err;
 31.1866 -
 31.1867 -	HandleSecurity sec;
 31.1868 -
 31.1869 -	sec.pOwner = NULL;
 31.1870 -	sec.pIdentity = m_MyIdent;
 31.1871 -
 31.1872 -	if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
 31.1873 -	{
 31.1874 -		pPlugin = NULL;
 31.1875 -	}
 31.1876 -
 31.1877 -	if (err)
 31.1878 -	{
 31.1879 -		*err = _err;
 31.1880 -	}
 31.1881 -
 31.1882 -	return pPlugin;
 31.1883 -}
 31.1884 -
 31.1885 -CPlugin *CPluginManager::GetPluginByOrder(int num)
 31.1886 -{
 31.1887 -	if (num < 1 || num > (int)GetPluginCount())
 31.1888 -	{
 31.1889 -		return NULL;
 31.1890 -	}
 31.1891 -
 31.1892 -	CPlugin *pl;
 31.1893 -	int id = 1;
 31.1894 -
 31.1895 -	SourceHook::List<CPlugin *>::iterator iter;
 31.1896 -	for (iter = m_plugins.begin(); iter != m_plugins.end() && id < num; iter++, id++) {}
 31.1897 -
 31.1898 -	pl = *iter;
 31.1899 -
 31.1900 -	return pl;
 31.1901 -}
 31.1902 -
 31.1903 -const char *CPluginManager::GetStatusText(PluginStatus st)
 31.1904 -{
 31.1905 -	switch (st)
 31.1906 -	{
 31.1907 -	case Plugin_Running:
 31.1908 -		return "Running";
 31.1909 -	case Plugin_Paused:
 31.1910 -		return "Paused";
 31.1911 -	case Plugin_Error:
 31.1912 -		return "Error";
 31.1913 -	case Plugin_Uncompiled:
 31.1914 -		return "Uncompiled";
 31.1915 -	case Plugin_BadLoad:
 31.1916 -		return "Bad Load";
 31.1917 -	case Plugin_Failed:
 31.1918 -		return "Failed";
 31.1919 -	default:
 31.1920 -		assert(false);
 31.1921 -		return "-";
 31.1922 -	}
 31.1923 -}
 31.1924 -
 31.1925 -void CPluginManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
 31.1926 -{
 31.1927 -	int argcount = command.ArgC();
 31.1928 -	if (argcount >= 3)
 31.1929 -	{
 31.1930 -		const char *cmd = command.Arg(2);
 31.1931 -		if (strcmp(cmd, "list") == 0)
 31.1932 -		{
 31.1933 -			char buffer[256];
 31.1934 -			unsigned int id = 1;
 31.1935 -			int plnum = GetPluginCount();
 31.1936 -
 31.1937 -			if (!plnum)
 31.1938 -			{
 31.1939 -				g_RootMenu.ConsolePrint("[SM] No plugins loaded");
 31.1940 -				return;
 31.1941 -			}
 31.1942 -			else
 31.1943 -			{
 31.1944 -				g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
 31.1945 -			}
 31.1946 -
 31.1947 -			CPlugin *pl;
 31.1948 -			SourceHook::List<CPlugin *>::iterator iter;
 31.1949 -			SourceHook::List<CPlugin *> m_FailList;
 31.1950 -
 31.1951 -			for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
 31.1952 -			{
 31.1953 -				pl = (*iter);
 31.1954 -				assert(pl->GetStatus() != Plugin_Created);
 31.1955 -				int len = 0;
 31.1956 -				const sm_plugininfo_t *info = pl->GetPublicInfo();
 31.1957 -				if (pl->GetStatus() != Plugin_Running)
 31.1958 -				{
 31.1959 -					len += UTIL_Format(buffer, sizeof(buffer), "  %02d <%s>", id, GetStatusText(pl->GetStatus()));
 31.1960 -
 31.1961 -					if (pl->GetStatus() <= Plugin_Error)
 31.1962 -					{
 31.1963 -						/* Plugin has failed to load. */
 31.1964 -						m_FailList.push_back(pl);
 31.1965 -					}
 31.1966 -				}
 31.1967 -				else
 31.1968 -				{
 31.1969 -					len += UTIL_Format(buffer, sizeof(buffer), "  %02d", id);
 31.1970 -				}
 31.1971 -				if (pl->GetStatus() < Plugin_Created)
 31.1972 -				{
 31.1973 -					len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 31.1974 -					if (IS_STR_FILLED(info->version))
 31.1975 -					{
 31.1976 -						len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
 31.1977 -					}
 31.1978 -					if (IS_STR_FILLED(info->author))
 31.1979 -					{
 31.1980 -						UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
 31.1981 -					}
 31.1982 -				}
 31.1983 -				else
 31.1984 -				{
 31.1985 -					UTIL_Format(&buffer[len], sizeof(buffer)-len, " %s", pl->m_filename);
 31.1986 -				}
 31.1987 -				g_RootMenu.ConsolePrint("%s", buffer);
 31.1988 -			}
 31.1989 -
 31.1990 -			if (!m_FailList.empty())
 31.1991 -			{
 31.1992 -				g_RootMenu.ConsolePrint("Load Errors:");
 31.1993 -
 31.1994 -				SourceHook::List<CPlugin *>::iterator _iter;
 31.1995 -
 31.1996 -				CPlugin *pl;
 31.1997 -
 31.1998 -				for (_iter=m_FailList.begin(); _iter!=m_FailList.end(); _iter++)
 31.1999 -				{
 31.2000 -					pl = (CPlugin *)*_iter;
 31.2001 -					g_RootMenu.ConsolePrint("%s: %s",(IS_STR_FILLED(pl->GetPublicInfo()->name)) ? pl->GetPublicInfo()->name : pl->GetFilename(), pl->m_errormsg);
 31.2002 -				}
 31.2003 -			}
 31.2004 -
 31.2005 -			return;
 31.2006 -		}
 31.2007 -		else if (strcmp(cmd, "load") == 0)
 31.2008 -		{
 31.2009 -			if (argcount < 4)
 31.2010 -			{
 31.2011 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load <file>");
 31.2012 -				return;
 31.2013 -			}
 31.2014 -
 31.2015 -			char error[128];
 31.2016 -			bool wasloaded;
 31.2017 -			const char *filename = command.Arg(3);
 31.2018 -
 31.2019 -			char pluginfile[256];
 31.2020 -			const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx";
 31.2021 -			UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext);
 31.2022 -
 31.2023 -			IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded);
 31.2024 -
 31.2025 -			if (wasloaded)
 31.2026 -			{
 31.2027 -				g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile);
 31.2028 -				return;
 31.2029 -			}
 31.2030 -
 31.2031 -			if (pl)
 31.2032 -			{
 31.2033 -				g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile);
 31.2034 -			}
 31.2035 -			else
 31.2036 -			{
 31.2037 -				g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error);
 31.2038 -			}
 31.2039 -
 31.2040 -			return;
 31.2041 -		}
 31.2042 -		else if (strcmp(cmd, "unload") == 0)
 31.2043 -		{
 31.2044 -			if (argcount < 4)
 31.2045 -			{
 31.2046 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#|file>");
 31.2047 -				return;
 31.2048 -			}
 31.2049 -
 31.2050 -			CPlugin *pl;
 31.2051 -			char *end;
 31.2052 -			const char *arg = command.Arg(3);
 31.2053 -			int id = strtol(arg, &end, 10);
 31.2054 -
 31.2055 -			if (*end == '\0')
 31.2056 -			{
 31.2057 -				pl = GetPluginByOrder(id);
 31.2058 -				if (!pl)
 31.2059 -				{
 31.2060 -					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 31.2061 -					return;
 31.2062 -				}
 31.2063 -			}
 31.2064 -			else
 31.2065 -			{
 31.2066 -				char pluginfile[256];
 31.2067 -				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 31.2068 -				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 31.2069 -
 31.2070 -				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 31.2071 -				{
 31.2072 -					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 31.2073 -					return;
 31.2074 -				}
 31.2075 -			}
 31.2076 -
 31.2077 -			char name[PLATFORM_MAX_PATH];
 31.2078 -
 31.2079 -			if (pl->GetStatus() < Plugin_Created)
 31.2080 -			{
 31.2081 -				const sm_plugininfo_t *info = pl->GetPublicInfo();
 31.2082 -				UTIL_Format(name, sizeof(name), (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 31.2083 -			}
 31.2084 -			else
 31.2085 -			{
 31.2086 -				UTIL_Format(name, sizeof(name), "%s", pl->GetFilename());
 31.2087 -			}
 31.2088 -
 31.2089 -			if (UnloadPlugin(pl))
 31.2090 -			{
 31.2091 -				g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name);
 31.2092 -			}
 31.2093 -			else
 31.2094 -			{
 31.2095 -				g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name);
 31.2096 -			}
 31.2097 -
 31.2098 -			return;
 31.2099 -		}
 31.2100 -		else if (strcmp(cmd, "unload_all") == 0)
 31.2101 -		{
 31.2102 -			g_PluginSys.UnloadAll();
 31.2103 -			g_RootMenu.ConsolePrint("[SM] All plugins have been unloaded.");
 31.2104 -			return;
 31.2105 -		}
 31.2106 -		else if (strcmp(cmd, "load_lock") == 0)
 31.2107 -		{
 31.2108 -			if (m_LoadingLocked)
 31.2109 -			{
 31.2110 -				g_RootMenu.ConsolePrint("[SM] There is already a loading lock in effect.");
 31.2111 -			}
 31.2112 -			else
 31.2113 -			{
 31.2114 -				m_LoadingLocked = true;
 31.2115 -				g_RootMenu.ConsolePrint("[SM] Loading is now locked; no plugins will be loaded or re-loaded.");
 31.2116 -			}
 31.2117 -			return;
 31.2118 -		}
 31.2119 -		else if (strcmp(cmd, "load_unlock") == 0)
 31.2120 -		{
 31.2121 -			if (m_LoadingLocked)
 31.2122 -			{
 31.2123 -				m_LoadingLocked = false;
 31.2124 -				g_RootMenu.ConsolePrint("[SM] The loading lock is no longer in effect.");
 31.2125 -			}
 31.2126 -			else
 31.2127 -			{
 31.2128 -				g_RootMenu.ConsolePrint("[SM] There was no loading lock in effect.");
 31.2129 -			}
 31.2130 -			return;
 31.2131 -		}
 31.2132 -		else if (strcmp(cmd, "info") == 0)
 31.2133 -		{
 31.2134 -			if (argcount < 4)
 31.2135 -			{
 31.2136 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>");
 31.2137 -				return;
 31.2138 -			}
 31.2139 -
 31.2140 -			CPlugin *pl;
 31.2141 -			char *end;
 31.2142 -			const char *arg = command.Arg(3);
 31.2143 -			int id = strtol(arg, &end, 10);
 31.2144 -
 31.2145 -			if (*end == '\0')
 31.2146 -			{
 31.2147 -				pl = GetPluginByOrder(id);
 31.2148 -				if (!pl)
 31.2149 -				{
 31.2150 -					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 31.2151 -					return;
 31.2152 -				}
 31.2153 -			}
 31.2154 -			else
 31.2155 -			{
 31.2156 -				char pluginfile[256];
 31.2157 -				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 31.2158 -				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 31.2159 -
 31.2160 -				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 31.2161 -				{
 31.2162 -					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 31.2163 -					return;
 31.2164 -				}
 31.2165 -			}
 31.2166 -
 31.2167 -			const sm_plugininfo_t *info = pl->GetPublicInfo();
 31.2168 -
 31.2169 -			g_RootMenu.ConsolePrint("  Filename: %s", pl->GetFilename());
 31.2170 -			if (pl->GetStatus() <= Plugin_Error)
 31.2171 -			{
 31.2172 -				if (IS_STR_FILLED(info->name))
 31.2173 -				{
 31.2174 -					if (IS_STR_FILLED(info->description))
 31.2175 -					{
 31.2176 -						g_RootMenu.ConsolePrint("  Title: %s (%s)", info->name, info->description);
 31.2177 -					} else {
 31.2178 -						g_RootMenu.ConsolePrint("  Title: %s", info->name);
 31.2179 -					}
 31.2180 -				}
 31.2181 -				if (IS_STR_FILLED(info->author))
 31.2182 -				{
 31.2183 -					g_RootMenu.ConsolePrint("  Author: %s", info->author);
 31.2184 -				}
 31.2185 -				if (IS_STR_FILLED(info->version))
 31.2186 -				{
 31.2187 -					g_RootMenu.ConsolePrint("  Version: %s", info->version);
 31.2188 -				}
 31.2189 -				if (IS_STR_FILLED(info->url))
 31.2190 -				{
 31.2191 -					g_RootMenu.ConsolePrint("  URL: %s", info->url);
 31.2192 -				}
 31.2193 -				if (pl->GetStatus() == Plugin_Error)
 31.2194 -				{
 31.2195 -					g_RootMenu.ConsolePrint("  Error: %s", pl->m_errormsg);
 31.2196 -				}
 31.2197 -				else
 31.2198 -				{
 31.2199 -					if (pl->GetStatus() == Plugin_Running)
 31.2200 -					{
 31.2201 -						g_RootMenu.ConsolePrint("  Status: running");
 31.2202 -					}
 31.2203 -					else
 31.2204 -					{
 31.2205 -						g_RootMenu.ConsolePrint("  Status: not running");
 31.2206 -					}
 31.2207 -
 31.2208 -					const char *typestr = "";
 31.2209 -					switch (pl->GetType())
 31.2210 -					{
 31.2211 -					case PluginType_MapUpdated:
 31.2212 -						typestr = "Map Change if Updated";
 31.2213 -						break;
 31.2214 -					case PluginType_MapOnly:
 31.2215 -						typestr = "Map Change";
 31.2216 -						break;
 31.2217 -					case PluginType_Private:
 31.2218 -					case PluginType_Global:
 31.2219 -						typestr = "Never";
 31.2220 -						break;
 31.2221 -					}
 31.2222 -
 31.2223 -					g_RootMenu.ConsolePrint("  Reloads: %s", typestr);
 31.2224 -				}
 31.2225 -				if (pl->m_FileVersion >= 3)
 31.2226 -				{
 31.2227 -					g_RootMenu.ConsolePrint("  Timestamp: %s", pl->m_DateTime);
 31.2228 -				}
 31.2229 -			}
 31.2230 -			else
 31.2231 -			{
 31.2232 -				g_RootMenu.ConsolePrint("  Load error: %s", pl->m_errormsg);
 31.2233 -				if (pl->GetStatus() < Plugin_Created)
 31.2234 -				{
 31.2235 -					g_RootMenu.ConsolePrint("  File info: (title \"%s\") (version \"%s\")", 
 31.2236 -											info->name ? info->name : "<none>",
 31.2237 -											info->version ? info->version : "<none>");
 31.2238 -					if (IS_STR_FILLED(info->url))
 31.2239 -					{
 31.2240 -						g_RootMenu.ConsolePrint("  File URL: %s", info->url);
 31.2241 -					}
 31.2242 -				}
 31.2243 -			}
 31.2244 -
 31.2245 -			return;
 31.2246 -		}
 31.2247 -		else if (strcmp(cmd, "refresh") == 0)
 31.2248 -		{
 31.2249 -			g_SourceMod.DoGlobalPluginLoads();
 31.2250 -			g_RootMenu.ConsolePrint("[SM] The plugin list has been refreshed and reloaded.");
 31.2251 -			return;
 31.2252 -		}
 31.2253 -		else if (strcmp(cmd, "reload") == 0)
 31.2254 -		{
 31.2255 -			if (argcount < 4)
 31.2256 -			{
 31.2257 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins reload <#|file>");
 31.2258 -				return;
 31.2259 -			}
 31.2260 -
 31.2261 -			CPlugin *pl;
 31.2262 -			char *end;
 31.2263 -			const char *arg = command.Arg(3);
 31.2264 -			int id = strtol(arg, &end, 10);
 31.2265 -
 31.2266 -			if (*end == '\0')
 31.2267 -			{
 31.2268 -				pl = GetPluginByOrder(id);
 31.2269 -				if (!pl)
 31.2270 -				{
 31.2271 -					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
 31.2272 -					return;
 31.2273 -				}
 31.2274 -			}
 31.2275 -			else
 31.2276 -			{
 31.2277 -				char pluginfile[256];
 31.2278 -				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 31.2279 -				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 31.2280 -
 31.2281 -				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 31.2282 -				{
 31.2283 -					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
 31.2284 -					return;
 31.2285 -				}
 31.2286 -			}
 31.2287 -
 31.2288 -			char name[PLATFORM_MAX_PATH];
 31.2289 -			const sm_plugininfo_t *info = pl->GetPublicInfo();
 31.2290 -			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
 31.2291 -
 31.2292 -			if (ReloadPlugin(pl))
 31.2293 -			{
 31.2294 -				g_RootMenu.ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
 31.2295 -			}
 31.2296 -			else
 31.2297 -			{
 31.2298 -				g_RootMenu.ConsolePrint("[SM] Failed to reload plugin %s.", name);
 31.2299 -			}
 31.2300 -
 31.2301 -			return;
 31.2302 -		}
 31.2303 -	}
 31.2304 -
 31.2305 -	/* Draw the main menu */
 31.2306 -	g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
 31.2307 -	g_RootMenu.DrawGenericOption("info", "Information about a plugin");
 31.2308 -	g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
 31.2309 -	g_RootMenu.DrawGenericOption("load", "Load a plugin");
 31.2310 -	g_RootMenu.DrawGenericOption("load_lock", "Prevents any more plugins from being loaded");
 31.2311 -	g_RootMenu.DrawGenericOption("load_unlock", "Re-enables plugin loading");
 31.2312 -	g_RootMenu.DrawGenericOption("refresh", "Reloads/refreshes all plugins in the plugins folder");
 31.2313 -	g_RootMenu.DrawGenericOption("reload", "Reloads a plugin");
 31.2314 -	g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
 31.2315 -	g_RootMenu.DrawGenericOption("unload_all", "Unloads all plugins");
 31.2316 -}
 31.2317 -
 31.2318 -bool CPluginManager::ReloadPlugin(CPlugin *pl)
 31.2319 -{
 31.2320 -	List<CPlugin *>::iterator iter;
 31.2321 -	char filename[PLATFORM_MAX_PATH];
 31.2322 -	bool wasloaded;
 31.2323 -	PluginType ptype;
 31.2324 -	IPlugin *newpl;
 31.2325 -	int id = 1;
 31.2326 -
 31.2327 -	strcpy(filename, pl->m_filename);
 31.2328 -	ptype = pl->GetType();
 31.2329 -
 31.2330 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++, id++)
 31.2331 -	{
 31.2332 -		if ((*iter) == pl)
 31.2333 -		{
 31.2334 -			break;
 31.2335 -		}
 31.2336 -	}
 31.2337 -
 31.2338 -	if (!UnloadPlugin(pl))
 31.2339 -	{
 31.2340 -		return false;
 31.2341 -	}
 31.2342 -	if (!(newpl=LoadPlugin(filename, true, ptype, NULL, 0, &wasloaded)))
 31.2343 -	{
 31.2344 -		return false;
 31.2345 -	}
 31.2346 -
 31.2347 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 31.2348 -	{
 31.2349 -		if ((*iter) == (CPlugin *)newpl)
 31.2350 -		{
 31.2351 -			m_plugins.erase(iter);
 31.2352 -			break;
 31.2353 -		}
 31.2354 -	}
 31.2355 -
 31.2356 -	int i;
 31.2357 -	for (i=1, iter=m_plugins.begin(); iter!=m_plugins.end() && i<id; iter++, i++)
 31.2358 -	{
 31.2359 -	}
 31.2360 -	m_plugins.insert(iter, (CPlugin *)newpl);
 31.2361 -
 31.2362 -	return true;
 31.2363 -}
 31.2364 -
 31.2365 -void CPluginManager::ReloadOrUnloadPlugins()
 31.2366 -{
 31.2367 -	/* If we're in a load lock, just skip this whole bit. */
 31.2368 -	if (m_LoadingLocked)
 31.2369 -	{
 31.2370 -		return;
 31.2371 -	}
 31.2372 -
 31.2373 -	List<CPlugin *>::iterator iter;
 31.2374 -	List<CPlugin *> tmp_list = m_plugins;
 31.2375 -	CPlugin *pl;
 31.2376 -	time_t t;
 31.2377 -
 31.2378 -	for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++)
 31.2379 -	{
 31.2380 -		pl = (*iter);
 31.2381 -		if (pl->GetType() ==  PluginType_MapOnly)
 31.2382 -		{
 31.2383 -			UnloadPlugin((IPlugin *)pl);
 31.2384 -		}
 31.2385 -		else if (pl->GetType() == PluginType_MapUpdated)
 31.2386 -		{
 31.2387 -			t = pl->GetFileTimeStamp();
 31.2388 -			if (!t || t > pl->GetTimeStamp())
 31.2389 -			{
 31.2390 -				pl->SetTimeStamp(t);
 31.2391 -				UnloadPlugin((IPlugin *)pl);
 31.2392 -			}
 31.2393 -		}
 31.2394 -	}
 31.2395 -}
 31.2396 -
 31.2397 -void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
 31.2398 -{
 31.2399 -	List<IPluginsListener *>::iterator iter;
 31.2400 -	IPluginsListener *pListener;
 31.2401 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
 31.2402 -	{
 31.2403 -		pListener = (*iter);
 31.2404 -		pListener->OnPluginPauseChange(pl, paused);
 31.2405 -	}	
 31.2406 -}
 31.2407 -
 31.2408 -void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward)
 31.2409 -{
 31.2410 -	List<CPlugin *>::iterator iter;
 31.2411 -	CPlugin *pPlugin;
 31.2412 -	IPluginFunction *pFunction;
 31.2413 -
 31.2414 -	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
 31.2415 -	{
 31.2416 -		pPlugin = (*iter);
 31.2417 -
 31.2418 -		if (pPlugin->GetStatus() <= Plugin_Paused)
 31.2419 -		{
 31.2420 -			pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name);
 31.2421 -
 31.2422 -			if (pFunction)
 31.2423 -			{
 31.2424 -				pForward->AddFunction(pFunction);
 31.2425 -			}
 31.2426 -		}
 31.2427 -	}
 31.2428 -}
 31.2429 -
 31.2430 -CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken)
 31.2431 -{
 31.2432 -	if (pToken->type != g_PluginIdent)
 31.2433 -	{
 31.2434 -		return NULL;
 31.2435 -	}
 31.2436 -
 31.2437 -	return (CPlugin *)(pToken->ptr);
 31.2438 -}
 31.2439 -
 31.2440 -void CPluginManager::OnLibraryAction(const char *lib, bool is_a_plugin, bool drop)
 31.2441 -{
 31.2442 -	List<CPlugin *>::iterator iter;
 31.2443 -
 31.2444 -	struct _pl
 31.2445 -	{
 31.2446 -		cell_t name;
 31.2447 -		cell_t file;
 31.2448 -		cell_t required;
 31.2449 -	} *plc;
 31.2450 -
 31.2451 -	struct _ext
 31.2452 -	{
 31.2453 -		cell_t name;
 31.2454 -		cell_t file;
 31.2455 -		cell_t autoload;
 31.2456 -		cell_t required;
 31.2457 -	} *ext;
 31.2458 -
 31.2459 -	const char *name = drop ? "OnLibraryRemoved" : "OnLibraryAdded";
 31.2460 -
 31.2461 -	for (iter=m_plugins.begin();
 31.2462 -		 iter!=m_plugins.end();
 31.2463 -		 iter++)
 31.2464 -	{
 31.2465 -		CPlugin *pl = (*iter);
 31.2466 -		if (pl->GetStatus() != Plugin_Running)
 31.2467 -		{
 31.2468 -			continue;
 31.2469 -		}
 31.2470 -		IPluginContext *pContext = pl->GetBaseContext();
 31.2471 -		IPluginFunction *pf = pContext->GetFunctionByName(name);
 31.2472 -		if (!pf)
 31.2473 -		{
 31.2474 -			continue;
 31.2475 -		}
 31.2476 -		uint32_t num_vars = pContext->GetPubVarsNum();
 31.2477 -		for (uint32_t i=0; i<num_vars; i++)
 31.2478 -		{
 31.2479 -			sp_pubvar_t *pubvar;
 31.2480 -			if (pContext->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
 31.2481 -			{
 31.2482 -				continue;
 31.2483 -			}
 31.2484 -			if (is_a_plugin && strncmp(pubvar->name, "__pl_", 5) == 0)
 31.2485 -			{
 31.2486 -				plc = (_pl *)pubvar->offs;
 31.2487 -				if (plc->required)
 31.2488 -				{
 31.2489 -					continue;
 31.2490 -				}
 31.2491 -				char *str;
 31.2492 -				pContext->LocalToString(plc->name, &str);
 31.2493 -				if (strcmp(str, lib) != 0)
 31.2494 -				{
 31.2495 -					continue;
 31.2496 -				}
 31.2497 -				pf->PushString(lib);
 31.2498 -				pf->Execute(NULL);
 31.2499 -			}
 31.2500 -			else if (!is_a_plugin && strncmp(pubvar->name, "__ext_", 6) == 0)
 31.2501 -			{
 31.2502 -				ext = (_ext *)pubvar->offs;
 31.2503 -				if (ext->required)
 31.2504 -				{
 31.2505 -					continue;
 31.2506 -				}
 31.2507 -				char *str;
 31.2508 -				pContext->LocalToString(ext->name, &str);
 31.2509 -				if (strcmp(str, lib) != 0)
 31.2510 -				{
 31.2511 -					continue;
 31.2512 -				}
 31.2513 -				pf->PushString(lib);
 31.2514 -				pf->Execute(NULL);
 31.2515 -			}
 31.2516 -		}
 31.2517 -	}
 31.2518 -}
 31.2519 -
 31.2520 -bool CPluginManager::LibraryExists(const char *lib)
 31.2521 -{
 31.2522 -	List<CPlugin *>::iterator iter;
 31.2523 -
 31.2524 -	for (iter=m_plugins.begin();
 31.2525 -		 iter!=m_plugins.end();
 31.2526 -		 iter++)
 31.2527 -	{
 31.2528 -		CPlugin *pl = (*iter);
 31.2529 -		if (pl->GetStatus() != Plugin_Running)
 31.2530 -		{
 31.2531 -			continue;
 31.2532 -		}
 31.2533 -		List<String>::iterator s_iter;
 31.2534 -		for (s_iter = pl->m_Libraries.begin();
 31.2535 -			 s_iter != pl->m_Libraries.end();
 31.2536 -			 s_iter++)
 31.2537 -		{
 31.2538 -			if ((*s_iter).compare(lib) == 0)
 31.2539 -			{
 31.2540 -				return true;
 31.2541 -			}
 31.2542 -		}
 31.2543 -	}
 31.2544 -
 31.2545 -	return false;
 31.2546 -}
 31.2547 -
 31.2548 -void CPluginManager::AllPluginsLoaded()
 31.2549 -{
 31.2550 -	List<CPlugin *>::iterator iter;
 31.2551 -	CPlugin *pl;
 31.2552 -
 31.2553 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
 31.2554 -	{
 31.2555 -		pl = (*iter);
 31.2556 -		pl->Call_OnAllPluginsLoaded();
 31.2557 -	}
 31.2558 -}
 31.2559 -
 31.2560 -void CPluginManager::UnloadAll()
 31.2561 -{
 31.2562 -	List<CPlugin *>::iterator iter;
 31.2563 -	while ( (iter = m_plugins.begin()) != m_plugins.end() )
 31.2564 -	{
 31.2565 -		UnloadPlugin((*iter));
 31.2566 -	}
 31.2567 -}
 31.2568 -
 31.2569 -int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
 31.2570 -{
 31.2571 -	int id = 1;
 31.2572 -	List<CPlugin *>::iterator iter;
 31.2573 -
 31.2574 -	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
 31.2575 -	{
 31.2576 -		if ((*iter) == pl)
 31.2577 -		{
 31.2578 -			return id;
 31.2579 -		}
 31.2580 -	}
 31.2581 -
 31.2582 -	return -1;
 31.2583 -}
 31.2584 -
 31.2585 -CPlugin *CPluginManager::FindPluginByConsoleArg(const char *arg)
 31.2586 -{
 31.2587 -	int id;
 31.2588 -	char *end;
 31.2589 -	CPlugin *pl;
 31.2590 -	
 31.2591 -	id = strtol(arg, &end, 10);
 31.2592 -
 31.2593 -	if (*end == '\0')
 31.2594 -	{
 31.2595 -		pl = GetPluginByOrder(id);
 31.2596 -		if (!pl)
 31.2597 -		{
 31.2598 -			return NULL;
 31.2599 -		}
 31.2600 -	}
 31.2601 -	else
 31.2602 -	{
 31.2603 -		char pluginfile[256];
 31.2604 -		const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
 31.2605 -		UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
 31.2606 -
 31.2607 -		if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
 31.2608 -		{
 31.2609 -			return NULL;
 31.2610 -		}
 31.2611 -	}
 31.2612 -
 31.2613 -	return pl;
 31.2614 -}
 31.2615 -
 31.2616 -void CPluginManager::OnSourceModMaxPlayersChanged(int newvalue)
 31.2617 -{
 31.2618 -	SyncMaxClients(newvalue);
 31.2619 -}
 31.2620 -
 31.2621 -void CPluginManager::SyncMaxClients(int max_clients)
 31.2622 -{
 31.2623 -	List<CPlugin *>::iterator iter;
 31.2624 -
 31.2625 -	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
 31.2626 -	{
 31.2627 -		(*iter)->SyncMaxClients(max_clients);
 31.2628 -	}
 31.2629 -}
    32.1 --- a/core/systems/PluginSys.h	Mon Nov 24 08:25:36 2008 -0600
    32.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.3 @@ -1,458 +0,0 @@
    32.4 -/**
    32.5 - * vim: set ts=4 :
    32.6 - * =============================================================================
    32.7 - * SourceMod
    32.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    32.9 - * =============================================================================
   32.10 - *
   32.11 - * This program is free software; you can redistribute it and/or modify it under
   32.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   32.13 - * Free Software Foundation.
   32.14 - * 
   32.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   32.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   32.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   32.18 - * details.
   32.19 - *
   32.20 - * You should have received a copy of the GNU General Public License along with
   32.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   32.22 - *
   32.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   32.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   32.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   32.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   32.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   32.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   32.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   32.30 - * or <http://www.sourcemod.net/license.php>.
   32.31 - *
   32.32 - * Version: $Id$
   32.33 - */
   32.34 -
   32.35 -#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
   32.36 -#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
   32.37 -
   32.38 -#include <time.h>
   32.39 -#include <errno.h>
   32.40 -#include <sys/stat.h>
   32.41 -#include <IPluginSys.h>
   32.42 -#include <IHandleSys.h>
   32.43 -#include <IForwardSys.h>
   32.44 -#include <sh_list.h>
   32.45 -#include <sh_stack.h>
   32.46 -#include <sh_vector.h>
   32.47 -#include <sh_string.h>
   32.48 -#include "sm_globals.h"
   32.49 -#include "PluginInfoDatabase.h"
   32.50 -#include "sm_trie.h"
   32.51 -#include "sourcemod.h"
   32.52 -#include <IRootConsoleMenu.h>
   32.53 -#if defined ORANGEBOX_BUILD
   32.54 -#include "convar_sm_ob.h"
   32.55 -#else
   32.56 -#include "convar_sm.h"
   32.57 -#endif
   32.58 -#include "ITranslator.h"
   32.59 -#include "NativeOwner.h"
   32.60 -#include "ShareSys.h"
   32.61 -
   32.62 -using namespace SourceHook;
   32.63 -
   32.64 -/**
   32.65 - * NOTES:
   32.66 - *
   32.67 - * UPDATE 2008-03-11: These comments are horribly out of date.  They paint a good overall 
   32.68 - * picture of how PluginSys works, but things like dependencies and fake natives have 
   32.69 - * complicated things quite a bit.
   32.70 - *
   32.71 - *  Currently this system needs a lot of work but it's good skeletally.  Plugin creation 
   32.72 - * is done without actually compiling anything.  This is done by Load functions in the 
   32.73 - * manager.  This will need a rewrite when we add context switching.
   32.74 - *
   32.75 - *  The plugin object itself has a few things to note.  The most important is that it stores
   32.76 - * a table of function objects.  The manager marshals allocation and freeing of these objects.
   32.77 - * The plugin object can be in erroneous states, they are:
   32.78 - *   Plugin_Error   --> Some error occurred any time during or after compilation.
   32.79 - *						This error can be cleared since the plugin itself is valid.
   32.80 - *						However, the state itself being set prevents any runtime action.
   32.81 - *   Plugin_BadLoad	--> The plugin failed to load entirely and nothing can be done to save it.
   32.82 - *
   32.83 - *  If a plugin fails to load externally, it is never added to the internal tracker.  However, 
   32.84 - * plugins that failed to load from the internal loading mechanism are always tracked.  This 
   32.85 - * allows users to see which automatically loaded plugins failed, and makes the interface a bit
   32.86 - * more flexible.
   32.87 - *
   32.88 - *  Once a plugin is compiled, it sets its own state to Plugin_Created.  This state is still invalid
   32.89 - * for execution.  SourceMod is a two pass system, and even though the second pass is not implemented
   32.90 - * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass.  When
   32.91 - * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
   32.92 - *
   32.93 - *  The two pass loading mechanism is described below.  Modules/natives are not implemented yet.
   32.94 - * PASS ONE: All loadable plugins are found and have the following steps performed:
   32.95 - *			 1.  Loading and compilation is attempted.
   32.96 - *			 2.  If successful, all natives from Core are added.
   32.97 - *			 3.  OnPluginLoad() is called.
   32.98 - *			 4.  If failed, any user natives are scrapped and the process halts here.
   32.99 - *			 5.  If successful, the plugin is ready for Pass 2.
  32.100 - * INTERMEDIATE:
  32.101 - *			 1.  All forced modules are loaded.
  32.102 - * PASS TWO: All loaded plugins are found and have these steps performed:
  32.103 - *			 1. Any modules referenced in the plugin that are not already loaded, are loaded.
  32.104 - *			 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
  32.105 - *			 3. If any natives are unresolved, check if they are found in the user-natives pool.
  32.106 - *			 4. If yes, load succeeds.  If not, natives are passed through a native acceptance filter.
  32.107 - *			 5. If the filter fails, the plugin is marked as failed.
  32.108 - *			 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
  32.109 - *			    Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
  32.110 - * PASS THREE (not a real pass):
  32.111 - *			 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
  32.112 - */
  32.113 -
  32.114 -enum LoadRes
  32.115 -{
  32.116 -	LoadRes_Successful,
  32.117 -	LoadRes_AlreadyLoaded,
  32.118 -	LoadRes_Failure,
  32.119 -	LoadRes_NeverLoad
  32.120 -};
  32.121 -
  32.122 -struct AutoConfig
  32.123 -{
  32.124 -	String autocfg;
  32.125 -	String folder;
  32.126 -	bool create;
  32.127 -};
  32.128 -
  32.129 -class CPlugin;
  32.130 -
  32.131 -class CPlugin : 
  32.132 -	public IPlugin,
  32.133 -	public CNativeOwner
  32.134 -{
  32.135 -	friend class CPluginManager;
  32.136 -	friend class CFunction;
  32.137 -public:
  32.138 -	CPlugin(const char *file);
  32.139 -	~CPlugin();
  32.140 -public:
  32.141 -	PluginType GetType();
  32.142 -	SourcePawn::IPluginContext *GetBaseContext();
  32.143 -	sp_context_t *GetContext();
  32.144 -	void *GetPluginStructure();
  32.145 -	const char *GetFilename();
  32.146 -	bool IsDebugging();
  32.147 -	PluginStatus GetStatus();
  32.148 -	const sm_plugininfo_t *GetPublicInfo();
  32.149 -	bool SetPauseState(bool paused);
  32.150 -	unsigned int GetSerial();
  32.151 -	IdentityToken_t *GetIdentity();
  32.152 -	unsigned int CalcMemUsage();
  32.153 -	bool SetProperty(const char *prop, void *ptr);
  32.154 -	bool GetProperty(const char *prop, void **ptr, bool remove=false);
  32.155 -	void DropEverything();
  32.156 -	SourcePawn::IPluginRuntime *GetRuntime();
  32.157 -public:
  32.158 -	/**
  32.159 -	 * Creates a plugin object with default values.
  32.160 -	 *   If an error buffer is specified, and an error occurs, the error will be copied to the buffer
  32.161 -	 * and NULL will be returned.
  32.162 -	 *   If an error buffer is not specified, the error will be copied to an internal buffer and 
  32.163 -	 * a valid (but error-stated) CPlugin will be returned.
  32.164 -	 */
  32.165 -	static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
  32.166 -public:
  32.167 -
  32.168 -	/**
  32.169 -	 * Sets an error state on the plugin
  32.170 -	 */
  32.171 -	void SetErrorState(PluginStatus status, const char *error_fmt, ...);
  32.172 -
  32.173 -	/**
  32.174 -	 * Initializes the plugin's identity information
  32.175 -	 */
  32.176 -	void InitIdentity();
  32.177 -
  32.178 -	/**
  32.179 -	 * Calls the OnPluginLoad function, and sets any failed states if necessary.
  32.180 -	 * NOTE: Valid pre-states are: Plugin_Created
  32.181 -	 * NOTE: If validated, plugin state is changed to Plugin_Loaded
  32.182 -	 *
  32.183 -	 * If the error buffer is NULL, the error message is cached locally.
  32.184 -	 */
  32.185 -	bool Call_AskPluginLoad(char *error, size_t maxlength);
  32.186 -
  32.187 -	/**
  32.188 -	 * Calls the OnPluginStart function.
  32.189 -	 * NOTE: Valid pre-states are: Plugin_Created
  32.190 -	 * NOTE: Post-state will be Plugin_Running
  32.191 -	 */
  32.192 -	void Call_OnPluginStart();
  32.193 -
  32.194 -	/**
  32.195 -	 * Calls the OnPluginEnd function.
  32.196 -	 */
  32.197 -	void Call_OnPluginEnd();
  32.198 -
  32.199 -	/**
  32.200 -	 * Calls the OnAllPluginsLoaded function.
  32.201 -	 */
  32.202 -	void Call_OnAllPluginsLoaded();
  32.203 -
  32.204 -	/**
  32.205 -	 * Returns true if a plugin is usable.
  32.206 -	 */
  32.207 -	bool IsRunnable();
  32.208 -
  32.209 -	/**
  32.210 -	 * Get languages info.
  32.211 -	 */
  32.212 -	IPhraseCollection *GetPhrases();
  32.213 -public:
  32.214 -	/**
  32.215 -	 * Returns the modification time during last plugin load.
  32.216 -	 */
  32.217 -	time_t GetTimeStamp();
  32.218 -
  32.219 -	/**
  32.220 -	 * Returns the current modification time of the plugin file.
  32.221 -	 */
  32.222 -	time_t GetFileTimeStamp();
  32.223 -
  32.224 -	/** 
  32.225 -	 * Returns true if the plugin was running, but is now invalid.
  32.226 -	 */
  32.227 -	bool WasRunning();
  32.228 -
  32.229 -	Handle_t GetMyHandle();
  32.230 -
  32.231 -	bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
  32.232 -	void AddConfig(bool autoCreate, const char *cfg, const char *folder);
  32.233 -	unsigned int GetConfigCount();
  32.234 -	AutoConfig *GetConfig(unsigned int i);
  32.235 -	inline void AddLibrary(const char *name)
  32.236 -	{
  32.237 -		m_Libraries.push_back(name);
  32.238 -	}
  32.239 -	void LibraryActions(bool dropping);
  32.240 -	void SyncMaxClients(int max_clients);
  32.241 -protected:
  32.242 -	bool UpdateInfo();
  32.243 -	void SetTimeStamp(time_t t);
  32.244 -	void DependencyDropped(CPlugin *pOwner);
  32.245 -private:
  32.246 -	PluginType m_type;
  32.247 -	char m_filename[PLATFORM_MAX_PATH];
  32.248 -	PluginStatus m_status;
  32.249 -	unsigned int m_serial;
  32.250 -	sm_plugininfo_t m_info;
  32.251 -	char m_errormsg[256];
  32.252 -	time_t m_LastAccess;
  32.253 -	IdentityToken_t *m_ident;
  32.254 -	Handle_t m_handle;
  32.255 -	bool m_WasRunning;
  32.256 -	IPhraseCollection *m_pPhrases;
  32.257 -	List<String> m_RequiredLibs;
  32.258 -	List<String> m_Libraries;
  32.259 -	Trie *m_pProps;
  32.260 -	bool m_FakeNativesMissing;
  32.261 -	bool m_LibraryMissing;
  32.262 -	CVector<AutoConfig *> m_configs;
  32.263 -	bool m_bGotAllLoaded;
  32.264 -	int m_FileVersion;
  32.265 -	char m_DateTime[256];
  32.266 -	IPluginRuntime *m_pRuntime;
  32.267 -	IPluginContext *m_pContext;
  32.268 -	sp_pubvar_t *m_MaxClientsVar;
  32.269 -};
  32.270 -
  32.271 -class CPluginManager : 
  32.272 -	public IPluginManager,
  32.273 -	public SMGlobalClass,
  32.274 -	public IHandleTypeDispatch,
  32.275 -	public IRootConsoleCommand
  32.276 -{
  32.277 -	friend class CPlugin;
  32.278 -public:
  32.279 -	CPluginManager();
  32.280 -	~CPluginManager();
  32.281 -public:
  32.282 -	/* Implements iterator class */
  32.283 -	class CPluginIterator : public IPluginIterator
  32.284 -	{
  32.285 -	public:
  32.286 -		CPluginIterator(List<CPlugin *> *mylist);
  32.287 -		virtual ~CPluginIterator();
  32.288 -		virtual bool MorePlugins();
  32.289 -		virtual IPlugin *GetPlugin();
  32.290 -		virtual void NextPlugin();
  32.291 -		void Release();
  32.292 -	public:
  32.293 -		void Reset();
  32.294 -	private:
  32.295 -		List<CPlugin *> *mylist;
  32.296 -		List<CPlugin *>::iterator current;
  32.297 -	};
  32.298 -	friend class CPluginManager::CPluginIterator;
  32.299 -public: //IPluginManager
  32.300 -	IPlugin *LoadPlugin(const char *path, 
  32.301 -								bool debug,
  32.302 -								PluginType type,
  32.303 -								char error[],
  32.304 -								size_t maxlength,
  32.305 -								bool *wasloaded);
  32.306 -	bool UnloadPlugin(IPlugin *plugin);
  32.307 -	IPlugin *FindPluginByContext(const sp_context_t *ctx);
  32.308 -	unsigned int GetPluginCount();
  32.309 -	IPluginIterator *GetPluginIterator();
  32.310 -	void AddPluginsListener(IPluginsListener *listener);
  32.311 -	void RemovePluginsListener(IPluginsListener *listener);
  32.312 -public: //SMGlobalClass
  32.313 -	void OnSourceModAllInitialized();
  32.314 -	void OnSourceModShutdown();
  32.315 -	void OnSourceModMaxPlayersChanged(int newvalue);
  32.316 -public: //IHandleTypeDispatch
  32.317 -	void OnHandleDestroy(HandleType_t type, void *object);
  32.318 -	bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
  32.319 -public: //IRootConsoleCommand
  32.320 -	void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
  32.321 -public:
  32.322 -	/**
  32.323 -	 * Loads all plugins not yet loaded
  32.324 -	 */
  32.325 -	void LoadAll_FirstPass(const char *config, const char *basedir);
  32.326 -
  32.327 -	/**
  32.328 -	 * Runs the second loading pass for all plugins
  32.329 -	 */
  32.330 -	void LoadAll_SecondPass();
  32.331 -
  32.332 -	/**
  32.333 -	 * Tests a plugin file mask against a local folder.
  32.334 -	 * The alias is searched backwards from localdir - i.e., given this input:
  32.335 -	 *   csdm/ban        csdm/ban
  32.336 -	 *   ban             csdm/ban
  32.337 -	 *   csdm/ban        optional/csdm/ban
  32.338 -	 * All of these will return true for an alias match.  
  32.339 -	 * Wildcards are allowed in the filename.
  32.340 -	 */
  32.341 -	bool TestAliasMatch(const char *alias, const char *localdir);
  32.342 -
  32.343 -	/** 
  32.344 -	 * Returns whether anything loaded will be a late load.
  32.345 -	 */
  32.346 -	bool IsLateLoadTime() const;
  32.347 -
  32.348 -	/**
  32.349 -	 * Converts a Handle to an IPlugin if possible.
  32.350 -	 */
  32.351 -	IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
  32.352 -
  32.353 -	/**
  32.354 -	 * Finds a plugin based on its index. (starts on index 1)
  32.355 -	 */
  32.356 -	CPlugin *GetPluginByOrder(int num);
  32.357 -
  32.358 -	int GetOrderOfPlugin(IPlugin *pl);
  32.359 -
  32.360 -	/** 
  32.361 -	 * Internal version of FindPluginByContext()
  32.362 -	 */
  32.363 -	CPlugin *GetPluginByCtx(const sp_context_t *ctx);
  32.364 -
  32.365 -	/**
  32.366 -	 * Gets status text for a status code 
  32.367 -	 */
  32.368 -	const char *GetStatusText(PluginStatus status);
  32.369 -
  32.370 -	/**
  32.371 -	* Reload or update plugins on level shutdown.
  32.372 -	*/
  32.373 -	void ReloadOrUnloadPlugins();
  32.374 -
  32.375 -	/**
  32.376 -	 * Add public functions from all running or paused
  32.377 -	 * plugins to the specified forward if the names match.
  32.378 -	 */
  32.379 -	void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
  32.380 -
  32.381 -	/**
  32.382 -	 * Iterates through plugins to call OnAllPluginsLoaded.
  32.383 -	 */
  32.384 -	void AllPluginsLoaded();
  32.385 -
  32.386 -	CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
  32.387 -
  32.388 -	void Shutdown();
  32.389 -
  32.390 -	void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
  32.391 -
  32.392 -	bool LibraryExists(const char *lib);
  32.393 -
  32.394 -	bool ReloadPlugin(CPlugin *pl);
  32.395 -
  32.396 -	void UnloadAll();
  32.397 -
  32.398 -	CPlugin *FindPluginByConsoleArg(const char *arg);
  32.399 -
  32.400 -	void SyncMaxClients(int max_clients);
  32.401 -private:
  32.402 -	LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
  32.403 -
  32.404 -	void LoadAutoPlugin(const char *plugin);
  32.405 -
  32.406 -	/**
  32.407 -	 * Recursively loads all plugins in the given directory.
  32.408 -	 */
  32.409 -	void LoadPluginsFromDir(const char *basedir, const char *localdir);
  32.410 -
  32.411 -	/**
  32.412 -	 * Adds a plugin object.  This is wrapped by LoadPlugin functions.
  32.413 -	 */
  32.414 -	void AddPlugin(CPlugin *pPlugin);
  32.415 -
  32.416 -	/**
  32.417 -	 * Runs the second loading pass on a plugin.
  32.418 -	 */
  32.419 -	bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
  32.420 -
  32.421 -	/**
  32.422 -	 * Runs an extension pass on a plugin.
  32.423 -	 */
  32.424 -	bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
  32.425 -
  32.426 -	/**
  32.427 -	* Manages required natives.
  32.428 -	*/
  32.429 -	bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
  32.430 -
  32.431 -	void _SetPauseState(CPlugin *pPlugin, bool pause);
  32.432 -protected:
  32.433 -	/**
  32.434 -	 * Caching internal objects
  32.435 -	 */
  32.436 -	void ReleaseIterator(CPluginIterator *iter);
  32.437 -public:
  32.438 -	inline IdentityToken_t *GetIdentity()
  32.439 -	{
  32.440 -		return m_MyIdent;
  32.441 -	}
  32.442 -private:
  32.443 -	void TryRefreshDependencies(CPlugin *pOther);
  32.444 -private:
  32.445 -	List<IPluginsListener *> m_listeners;
  32.446 -	List<CPlugin *> m_plugins;
  32.447 -	CStack<CPluginManager::CPluginIterator *> m_iters;
  32.448 -	CPluginInfoDatabase m_PluginInfo;
  32.449 -	Trie *m_LoadLookup;
  32.450 -	bool m_AllPluginsLoaded;
  32.451 -	IdentityToken_t *m_MyIdent;
  32.452 -
  32.453 -	/* Dynamic native stuff */
  32.454 -	List<FakeNative *> m_Natives;
  32.455 -
  32.456 -	bool m_LoadingLocked;
  32.457 -};
  32.458 -
  32.459 -extern CPluginManager g_PluginSys;
  32.460 -
  32.461 -#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
    33.1 --- a/core/systems/ShareSys.cpp	Mon Nov 24 08:25:36 2008 -0600
    33.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.3 @@ -1,529 +0,0 @@
    33.4 -/**
    33.5 - * vim: set ts=4 :
    33.6 - * =============================================================================
    33.7 - * SourceMod
    33.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    33.9 - * =============================================================================
   33.10 - *
   33.11 - * This program is free software; you can redistribute it and/or modify it under
   33.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   33.13 - * Free Software Foundation.
   33.14 - * 
   33.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   33.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   33.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   33.18 - * details.
   33.19 - *
   33.20 - * You should have received a copy of the GNU General Public License along with
   33.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   33.22 - *
   33.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   33.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   33.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   33.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   33.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   33.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   33.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   33.30 - * or <http://www.sourcemod.net/license.php>.
   33.31 - *
   33.32 - * Version: $Id$
   33.33 - */
   33.34 -
   33.35 -#include "ShareSys.h"
   33.36 -#include "HandleSys.h"
   33.37 -#include "ExtensionSys.h"
   33.38 -#include "LibrarySys.h"
   33.39 -#include "PluginSys.h"
   33.40 -#include "sm_stringutil.h"
   33.41 -
   33.42 -ShareSystem g_ShareSys;
   33.43 -static unsigned int g_mark_serial = 0;
   33.44 -
   33.45 -ShareSystem::ShareSystem()
   33.46 -{
   33.47 -	m_IdentRoot.ident = 0;
   33.48 -	m_TypeRoot = 0;
   33.49 -	m_IfaceType = 0;
   33.50 -	m_CoreType = 0;
   33.51 -}
   33.52 -
   33.53 -IdentityToken_t *ShareSystem::CreateCoreIdentity()
   33.54 -{
   33.55 -	if (!m_CoreType)
   33.56 -	{
   33.57 -		m_CoreType = CreateIdentType("CORE");
   33.58 -	}
   33.59 -
   33.60 -	return CreateIdentity(m_CoreType, this);
   33.61 -}
   33.62 -
   33.63 -void ShareSystem::Initialize()
   33.64 -{
   33.65 -	TypeAccess sec;
   33.66 -
   33.67 -	g_HandleSys.InitAccessDefaults(&sec, NULL);
   33.68 -	sec.ident = GetIdentRoot();
   33.69 -
   33.70 -	m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
   33.71 -	m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
   33.72 -
   33.73 -	/* Initialize our static identity handle */
   33.74 -	m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
   33.75 -
   33.76 -	/* Add the Handle System and others... they are too innocent and pure to do it themselves */
   33.77 -	AddInterface(NULL, &g_HandleSys);
   33.78 -	AddInterface(NULL, &g_LibSys);
   33.79 -}
   33.80 -
   33.81 -void ShareSystem::OnSourceModShutdown()
   33.82 -{
   33.83 -	if (m_CoreType)
   33.84 -	{
   33.85 -		g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
   33.86 -	}
   33.87 -
   33.88 -	g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
   33.89 -	g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
   33.90 -}
   33.91 -
   33.92 -IdentityType_t ShareSystem::FindIdentType(const char *name)
   33.93 -{
   33.94 -	HandleType_t type;
   33.95 -
   33.96 -	if (g_HandleSys.FindHandleType(name, &type))
   33.97 -	{
   33.98 -		if (g_HandleSys.TypeCheck(type, m_TypeRoot))
   33.99 -		{
  33.100 -			return type;
  33.101 -		}
  33.102 -	}
  33.103 -
  33.104 -	return 0;
  33.105 -}
  33.106 -
  33.107 -IdentityType_t ShareSystem::CreateIdentType(const char *name)
  33.108 -{
  33.109 -	if (!m_TypeRoot)
  33.110 -	{
  33.111 -		return 0;
  33.112 -	}
  33.113 -
  33.114 -	return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
  33.115 -}
  33.116 -
  33.117 -void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
  33.118 -{
  33.119 -	/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
  33.120 -}
  33.121 -
  33.122 -IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
  33.123 -{
  33.124 -	if (!m_TypeRoot)
  33.125 -	{
  33.126 -		return 0;
  33.127 -	}
  33.128 -
  33.129 -	/* :TODO: Cache? */
  33.130 -	IdentityToken_t *pToken = new IdentityToken_t;
  33.131 -
  33.132 -	HandleSecurity sec;
  33.133 -	sec.pOwner = sec.pIdentity = GetIdentRoot();
  33.134 -
  33.135 -	pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
  33.136 -	pToken->ptr = ptr;
  33.137 -	pToken->type = type;
  33.138 -
  33.139 -	return pToken;
  33.140 -}
  33.141 -
  33.142 -bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
  33.143 -{
  33.144 -	if (!iface)
  33.145 -	{
  33.146 -		return false;
  33.147 -	}
  33.148 -
  33.149 -	IfaceInfo info;
  33.150 -
  33.151 -	info.owner = myself;
  33.152 -	info.iface = iface;
  33.153 -	
  33.154 -	m_Interfaces.push_back(info);
  33.155 -
  33.156 -	return true;
  33.157 -}
  33.158 -
  33.159 -bool ShareSystem::RequestInterface(const char *iface_name, 
  33.160 -								   unsigned int iface_vers, 
  33.161 -								   IExtension *myself, 
  33.162 -								   SMInterface **pIface)
  33.163 -{
  33.164 -	/* See if the interface exists */
  33.165 -	List<IfaceInfo>::iterator iter;
  33.166 -	SMInterface *iface;
  33.167 -	IExtension *iface_owner;
  33.168 -	bool found = false;
  33.169 -	for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
  33.170 -	{
  33.171 -		IfaceInfo &info = (*iter);
  33.172 -		iface = info.iface;
  33.173 -		if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
  33.174 -		{
  33.175 -			if (iface->GetInterfaceVersion() == iface_vers
  33.176 -				|| iface->IsVersionCompatible(iface_vers))
  33.177 -			{
  33.178 -				iface_owner = info.owner;
  33.179 -				found = true;
  33.180 -				break;
  33.181 -			}
  33.182 -		}
  33.183 -	}
  33.184 -
  33.185 -	if (!found)
  33.186 -	{
  33.187 -		return false;
  33.188 -	}
  33.189 -
  33.190 -	/* Add a dependency node */
  33.191 -	if (iface_owner)
  33.192 -	{
  33.193 -		IfaceInfo info;
  33.194 -		info.iface = iface;
  33.195 -		info.owner = iface_owner;
  33.196 -		g_Extensions.BindDependency(myself, &info);
  33.197 -	}
  33.198 -
  33.199 -	if (pIface)
  33.200 -	{
  33.201 -		*pIface = iface;
  33.202 -	}
  33.203 -
  33.204 -	return true;
  33.205 -}
  33.206 -
  33.207 -void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
  33.208 -{
  33.209 -	CNativeOwner *pOwner;
  33.210 -
  33.211 -	pOwner = g_Extensions.GetNativeOwner(myself);
  33.212 -
  33.213 -	pOwner->AddNatives(natives);
  33.214 -}
  33.215 -
  33.216 -void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
  33.217 -{
  33.218 -	HandleSecurity sec;
  33.219 -
  33.220 -	sec.pOwner = GetIdentRoot();
  33.221 -	sec.pIdentity = GetIdentRoot();
  33.222 -
  33.223 -	g_HandleSys.FreeHandle(identity->ident, &sec);
  33.224 -	delete identity;
  33.225 -}
  33.226 -
  33.227 -void ShareSystem::DestroyIdentType(IdentityType_t type)
  33.228 -{
  33.229 -	g_HandleSys.RemoveType(type, GetIdentRoot());
  33.230 -}
  33.231 -
  33.232 -void ShareSystem::RemoveInterfaces(IExtension *pExtension)
  33.233 -{
  33.234 -	List<IfaceInfo>::iterator iter = m_Interfaces.begin();
  33.235 -
  33.236 -	while (iter != m_Interfaces.end())
  33.237 -	{
  33.238 -		if ((*iter).owner == pExtension)
  33.239 -		{
  33.240 -			iter = m_Interfaces.erase(iter);
  33.241 -		}
  33.242 -		else
  33.243 -		{
  33.244 -			iter++;
  33.245 -		}
  33.246 -	}
  33.247 -}
  33.248 -
  33.249 -void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
  33.250 -{
  33.251 -	g_Extensions.AddDependency(myself, filename, require, autoload);
  33.252 -}
  33.253 -
  33.254 -void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
  33.255 -{
  33.256 -	g_Extensions.AddLibrary(myself, name);
  33.257 -}
  33.258 -
  33.259 -void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
  33.260 -{
  33.261 -	unsigned int i;
  33.262 -	NativeEntry *pEntry;
  33.263 -	CNativeOwner *pOwner;
  33.264 -
  33.265 -	pOwner = g_Extensions.GetNativeOwner(myself);
  33.266 -
  33.267 -	for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
  33.268 -	{
  33.269 -		if ((pEntry = FindNative(natives[i].name)) == NULL)
  33.270 -		{
  33.271 -			continue;
  33.272 -		}
  33.273 -
  33.274 -		if (pEntry->owner != g_pCoreNatives)
  33.275 -		{
  33.276 -			continue;
  33.277 -		}
  33.278 -
  33.279 -		if (pEntry->replacement.owner != NULL)
  33.280 -		{
  33.281 -			continue;
  33.282 -		}
  33.283 -
  33.284 -		/* Now it's safe to add the override */
  33.285 -		pEntry->replacement.func = natives[i].func;
  33.286 -		pEntry->replacement.owner = pOwner;
  33.287 -		pOwner->AddReplacedNative(pEntry);
  33.288 -	}
  33.289 -}
  33.290 -
  33.291 -NativeEntry *ShareSystem::FindNative(const char *name)
  33.292 -{
  33.293 -	NativeEntry **ppEntry;
  33.294 -
  33.295 -	if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
  33.296 -	{
  33.297 -		return NULL;
  33.298 -	}
  33.299 -
  33.300 -	return *ppEntry;
  33.301 -}
  33.302 -
  33.303 -void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
  33.304 -{
  33.305 -	NativeEntry *pEntry;
  33.306 -	sp_native_t *native;
  33.307 -	uint32_t i, native_count;
  33.308 -	IPluginContext *pContext;
  33.309 -
  33.310 -	pContext = pPlugin->GetBaseContext();
  33.311 -
  33.312 -	/* Generate a new serial ID, mark our dependencies with it. */
  33.313 -	g_mark_serial++;
  33.314 -	pPlugin->PropogateMarkSerial(g_mark_serial);
  33.315 -
  33.316 -	native_count = pContext->GetNativesNum();
  33.317 -	for (i = 0; i < native_count; i++)
  33.318 -	{
  33.319 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  33.320 -		{
  33.321 -			continue;
  33.322 -		}
  33.323 -
  33.324 -		/* If we're bound, check if there is a replacement available.  
  33.325 -		 * If not, this native is totally finalized.
  33.326 -		 */
  33.327 -		if (native->status == SP_NATIVE_BOUND)
  33.328 -		{
  33.329 -			pEntry = (NativeEntry *)native->user;
  33.330 -			assert(pEntry != NULL);
  33.331 -			if (pEntry->replacement.owner == NULL
  33.332 -				|| (pEntry->replacement.owner != NULL 
  33.333 -				&&  pEntry->replacement.func == native->pfn))
  33.334 -			{
  33.335 -				continue;
  33.336 -			}
  33.337 -		}
  33.338 -		/* Otherwise, the native must be in our cache. */
  33.339 -		else if ((pEntry = FindNative(native->name)) == NULL)
  33.340 -		{
  33.341 -			continue;
  33.342 -		}
  33.343 -
  33.344 -		if (bCoreOnly && pEntry->owner != g_pCoreNatives)
  33.345 -		{
  33.346 -			continue;
  33.347 -		}
  33.348 -
  33.349 -		BindNativeToPlugin(pPlugin, native, i, pEntry);
  33.350 -	}
  33.351 -}
  33.352 -
  33.353 -void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
  33.354 -{
  33.355 -	uint32_t i;
  33.356 -	sp_native_t *native;
  33.357 -	IPluginContext *pContext;
  33.358 -
  33.359 -	pContext = pPlugin->GetBaseContext();
  33.360 -
  33.361 -	if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
  33.362 -	{
  33.363 -		return;
  33.364 -	}
  33.365 -	if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  33.366 -	{
  33.367 -		return;
  33.368 -	}
  33.369 -
  33.370 -	if (native->status == SP_NATIVE_BOUND)
  33.371 -	{
  33.372 -		return;
  33.373 -	}
  33.374 -
  33.375 -	BindNativeToPlugin(pPlugin, native, i, pEntry);
  33.376 -}
  33.377 -
  33.378 -void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, 
  33.379 -									 sp_native_t *native,
  33.380 -									 uint32_t index,
  33.381 -									 NativeEntry *pEntry)
  33.382 -{
  33.383 -	/* Mark as bound... we do the rest next. */
  33.384 -	native->status = SP_NATIVE_BOUND;
  33.385 -	native->user = pEntry;
  33.386 -
  33.387 -	/* See if a replacement is available. */
  33.388 -	if (pEntry->replacement.owner != NULL)
  33.389 -	{
  33.390 -		/* Perform a replacement bind. */
  33.391 -		native->pfn = pEntry->replacement.func;
  33.392 -		pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
  33.393 -	}
  33.394 -	else
  33.395 -	{
  33.396 -		/* Perform a normal bind. */
  33.397 -		native->pfn = pEntry->func;
  33.398 -
  33.399 -		/* We don't bother with dependency crap if the owner is Core. */
  33.400 -		if (pEntry->owner != g_pCoreNatives)
  33.401 -		{
  33.402 -			/* The native is optional, this is a special case */
  33.403 -			if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
  33.404 -			{
  33.405 -				/* Only add if there is a valid owner. */
  33.406 -				if (pEntry->owner != NULL)
  33.407 -				{
  33.408 -					pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
  33.409 -				}
  33.410 -				else
  33.411 -				{
  33.412 -					native->status = SP_NATIVE_UNBOUND;
  33.413 -				}
  33.414 -			}
  33.415 -			/* Otherwise, we're a strong dependent and not a weak one */
  33.416 -			else
  33.417 -			{
  33.418 -				/* See if this has already been marked as a dependent.
  33.419 -				 * If it has, it means this relationship has already occurred, 
  33.420 -				 * and there is no reason to do it again.
  33.421 -				 */
  33.422 -				if (pEntry->owner != pPlugin 
  33.423 -					&& pEntry->owner->GetMarkSerial() != g_mark_serial)
  33.424 -				{
  33.425 -					/* This has not been marked as a dependency yet */
  33.426 -					//pPlugin->AddDependency(pEntry->owner);
  33.427 -					pEntry->owner->AddDependent(pPlugin);
  33.428 -					pEntry->owner->SetMarkSerial(g_mark_serial);
  33.429 -				}
  33.430 -			}
  33.431 -		}
  33.432 -	}
  33.433 -}
  33.434 -
  33.435 -NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
  33.436 -{
  33.437 -	NativeEntry *pEntry;
  33.438 -
  33.439 -	if ((pEntry = FindNative(ntv->name)) == NULL)
  33.440 -	{
  33.441 -		pEntry = new NativeEntry;
  33.442 -
  33.443 -		pEntry->owner = pOwner;
  33.444 -		pEntry->name = ntv->name;
  33.445 -		pEntry->func = ntv->func;
  33.446 -		pEntry->replacement.func = NULL;
  33.447 -		pEntry->replacement.owner = NULL;
  33.448 -		pEntry->fake = NULL;
  33.449 -
  33.450 -		m_NtvCache.insert(ntv->name, pEntry);
  33.451 -
  33.452 -		return pEntry;
  33.453 -	}
  33.454 -
  33.455 -	if (pEntry->owner != NULL)
  33.456 -	{
  33.457 -		return NULL;
  33.458 -	}
  33.459 -
  33.460 -	pEntry->owner = pOwner;
  33.461 -	pEntry->func = ntv->func;
  33.462 -	pEntry->name = ntv->name;
  33.463 -
  33.464 -	return pEntry;
  33.465 -}
  33.466 -
  33.467 -void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
  33.468 -{
  33.469 -	NativeEntry *pEntry;
  33.470 -
  33.471 -	if ((pEntry = FindNative(name)) == NULL)
  33.472 -	{
  33.473 -		return;
  33.474 -	}
  33.475 -
  33.476 -	if (pEntry->owner != pOwner)
  33.477 -	{
  33.478 -		return;
  33.479 -	}
  33.480 -
  33.481 -	if (pEntry->fake != NULL)
  33.482 -	{
  33.483 -		g_pSourcePawn2->DestroyFakeNative(pEntry->func);
  33.484 -		delete pEntry->fake;
  33.485 -		pEntry->fake = NULL;
  33.486 -	}
  33.487 -
  33.488 -	pEntry->func = NULL;
  33.489 -	pEntry->name = NULL;
  33.490 -	pEntry->owner = NULL;
  33.491 -	pEntry->replacement.func = NULL;
  33.492 -	pEntry->replacement.owner = NULL;
  33.493 -}
  33.494 -
  33.495 -NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
  33.496 -{
  33.497 -	FakeNative *pFake;
  33.498 -	NativeEntry *pEntry;
  33.499 -	SPVM_NATIVE_FUNC gate;
  33.500 -
  33.501 -	if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
  33.502 -	{
  33.503 -		return NULL;
  33.504 -	}
  33.505 -
  33.506 -	pFake = new FakeNative;
  33.507 -
  33.508 -	if ((gate = g_pSourcePawn2->CreateFakeNative(func, pFake)) == NULL)
  33.509 -	{
  33.510 -		delete pFake;
  33.511 -		return NULL;
  33.512 -	}
  33.513 -
  33.514 -	if (pEntry == NULL)
  33.515 -	{
  33.516 -		pEntry = new NativeEntry;
  33.517 -		m_NtvCache.insert(name, pEntry);
  33.518 -	}
  33.519 -
  33.520 -	pFake->call = pFunc;
  33.521 -	pFake->ctx = pFunc->GetParentContext();
  33.522 -	strncopy(pFake->name, name, sizeof(pFake->name));
  33.523 -	
  33.524 -	pEntry->fake = pFake;
  33.525 -	pEntry->func = gate;
  33.526 -	pEntry->name = pFake->name;
  33.527 -	pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
  33.528 -	pEntry->replacement.func = NULL;
  33.529 -	pEntry->replacement.owner = NULL;
  33.530 -
  33.531 -	return pEntry;
  33.532 -}
    34.1 --- a/core/systems/ShareSys.h	Mon Nov 24 08:25:36 2008 -0600
    34.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.3 @@ -1,150 +0,0 @@
    34.4 -/**
    34.5 - * vim: set ts=4 :
    34.6 - * =============================================================================
    34.7 - * SourceMod
    34.8 - * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
    34.9 - * =============================================================================
   34.10 - *
   34.11 - * This program is free software; you can redistribute it and/or modify it under
   34.12 - * the terms of the GNU General Public License, version 3.0, as published by the
   34.13 - * Free Software Foundation.
   34.14 - * 
   34.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
   34.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   34.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
   34.18 - * details.
   34.19 - *
   34.20 - * You should have received a copy of the GNU General Public License along with
   34.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
   34.22 - *
   34.23 - * As a special exception, AlliedModders LLC gives you permission to link the
   34.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
   34.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
   34.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
   34.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
   34.28 - * this exception to all derivative works.  AlliedModders LLC defines further
   34.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
   34.30 - * or <http://www.sourcemod.net/license.php>.
   34.31 - *
   34.32 - * Version: $Id$
   34.33 - */
   34.34 -
   34.35 -#ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
   34.36 -#define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
   34.37 -
   34.38 -#include <IShareSys.h>
   34.39 -#include <IHandleSys.h>
   34.40 -#include <sh_list.h>
   34.41 -#include <sm_trie_tpl.h>
   34.42 -#include "sm_globals.h"
   34.43 -#include "sourcemod.h"
   34.44 -
   34.45 -using namespace SourceHook;
   34.46 -
   34.47 -namespace SourceMod
   34.48 -{
   34.49 -	struct IdentityToken_t
   34.50 -	{
   34.51 -		Handle_t ident;
   34.52 -		void *ptr;
   34.53 -		IdentityType_t type;
   34.54 -	};
   34.55 -};
   34.56 -
   34.57 -struct IfaceInfo
   34.58 -{
   34.59 -	bool operator ==(const IfaceInfo &info)
   34.60 -	{
   34.61 -		return (info.iface == iface && info.owner == owner);
   34.62 -	}
   34.63 -	SMInterface *iface;
   34.64 -	IExtension *owner;
   34.65 -};
   34.66 -
   34.67 -class CNativeOwner;
   34.68 -class CPlugin;
   34.69 -struct NativeEntry;
   34.70 -
   34.71 -struct ReplaceNative
   34.72 -{
   34.73 -	CNativeOwner *owner;
   34.74 -	SPVM_NATIVE_FUNC func;
   34.75 -};
   34.76 -
   34.77 -struct FakeNative
   34.78 -{
   34.79 -	char name[64];
   34.80 -	IPluginContext *ctx;
   34.81 -	IPluginFunction *call;
   34.82 -};
   34.83 -
   34.84 -struct NativeEntry
   34.85 -{
   34.86 -	CNativeOwner *owner;
   34.87 -	SPVM_NATIVE_FUNC func;
   34.88 -	const char *name;
   34.89 -	ReplaceNative replacement;
   34.90 -	FakeNative *fake;
   34.91 -};
   34.92 -
   34.93 -class ShareSystem : 
   34.94 -	public IShareSys,
   34.95 -	public SMGlobalClass,
   34.96 -	public IHandleTypeDispatch
   34.97 -{
   34.98 -	friend class CNativeOwner;
   34.99 -public:
  34.100 -	ShareSystem();
  34.101 -public: //IShareSys
  34.102 -	bool AddInterface(IExtension *myself, SMInterface *pIface);
  34.103 -	bool RequestInterface(const char *iface_name, 
  34.104 -		unsigned int iface_vers,
  34.105 -		IExtension *myself,
  34.106 -		SMInterface **pIface);
  34.107 -	void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives);
  34.108 -	IdentityType_t CreateIdentType(const char *name);
  34.109 -	IdentityType_t FindIdentType(const char *name);
  34.110 -	IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr);
  34.111 -	void DestroyIdentType(IdentityType_t type);
  34.112 -	void DestroyIdentity(IdentityToken_t *identity);
  34.113 -	void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
  34.114 -	void RegisterLibrary(IExtension *myself, const char *name);
  34.115 -	void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
  34.116 -public: //SMGlobalClass
  34.117 -	/* Pre-empt in case anything tries to register idents early */
  34.118 -	void Initialize();
  34.119 -	void OnSourceModShutdown();
  34.120 -public: //IHandleTypeDispatch
  34.121 -	void OnHandleDestroy(HandleType_t type, void *object);
  34.122 -public:
  34.123 -	IdentityToken_t *CreateCoreIdentity();
  34.124 -	void RemoveInterfaces(IExtension *pExtension);
  34.125 -public:
  34.126 -	inline IdentityToken_t *GetIdentRoot()
  34.127 -	{
  34.128 -		return &m_IdentRoot;
  34.129 -	}
  34.130 -public:
  34.131 -	void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
  34.132 -	void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
  34.133 -	NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
  34.134 -private:
  34.135 -	NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
  34.136 -	void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
  34.137 -	NativeEntry *FindNative(const char *name);
  34.138 -	void BindNativeToPlugin(CPlugin *pPlugin, 
  34.139 -		sp_native_t *ntv, 
  34.140 -		uint32_t index, 
  34.141 -		NativeEntry *pEntry);
  34.142 -private:
  34.143 -	List<IfaceInfo> m_Interfaces;
  34.144 -	HandleType_t m_TypeRoot;
  34.145 -	IdentityToken_t m_IdentRoot;
  34.146 -	HandleType_t m_IfaceType;
  34.147 -	IdentityType_t m_CoreType;
  34.148 -	KTrie<NativeEntry *> m_NtvCache;
  34.149 -};
  34.150 -
  34.151 -extern ShareSystem g_ShareSys;
  34.152 -
  34.153 -#endif //_INCLUDE_SOURCEMOD_SHARESYSTEM_H_