Merge.
Merge.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/ExtensionSys.cpp Wed Nov 19 02:16:45 2008 -0600
1.3 @@ -0,0 +1,1210 @@
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 SOURCE_ENGINE == SE_LEFT4DEAD
1.76 + "extensions/auto.2.l4d/%s",
1.77 +#elif SOURCE_ENGINE == SE_ORANGEBOX
1.78 + "extensions/auto.2.ep2/%s",
1.79 +#else
1.80 + "extensions/auto.2.ep1/%s",
1.81 +#endif //SOURCE_ENGINE == SE_LEFT4DEAD
1.82 +#else //METAMOD_PLAPI_VERSION
1.83 + "extensions/auto.1.ep1/%s",
1.84 +#endif //METAMOD_PLAPI_VERSION
1.85 + filename);
1.86 +
1.87 + /* Try the "normal" version */
1.88 + if (!g_LibSys.IsPathFile(path))
1.89 + {
1.90 + g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
1.91 + }
1.92 +
1.93 + Initialize(filename, path);
1.94 +}
1.95 +
1.96 +bool CRemoteExtension::Load(char *error, size_t maxlength)
1.97 +{
1.98 + if (!PerformAPICheck(error, maxlength))
1.99 + {
1.100 + m_pAPI = NULL;
1.101 + return false;
1.102 + }
1.103 +
1.104 + if (!CExtension::Load(error, maxlength))
1.105 + {
1.106 + m_pAPI = NULL;
1.107 + return false;
1.108 + }
1.109 +
1.110 + return true;
1.111 +}
1.112 +
1.113 +bool CLocalExtension::Load(char *error, size_t maxlength)
1.114 +{
1.115 + m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
1.116 +
1.117 + if (m_pLib == NULL)
1.118 + {
1.119 + return false;
1.120 + }
1.121 +
1.122 + typedef IExtensionInterface *(*GETAPI)();
1.123 + GETAPI pfnGetAPI = NULL;
1.124 +
1.125 + if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
1.126 + {
1.127 + m_pLib->CloseLibrary();
1.128 + m_pLib = NULL;
1.129 + snprintf(error, maxlength, "Unable to find extension entry point");
1.130 + return false;
1.131 + }
1.132 +
1.133 + m_pAPI = pfnGetAPI();
1.134 +
1.135 + /* Check pointer and version */
1.136 + if (!PerformAPICheck(error, maxlength))
1.137 + {
1.138 + m_pLib->CloseLibrary();
1.139 + m_pLib = NULL;
1.140 + m_pAPI = NULL;
1.141 + return false;
1.142 + }
1.143 +
1.144 + /* Load as MM:S */
1.145 + if (m_pAPI->IsMetamodExtension())
1.146 + {
1.147 + bool already;
1.148 + m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
1.149 + }
1.150 +
1.151 + if (!CExtension::Load(error, maxlength))
1.152 + {
1.153 + if (m_pAPI->IsMetamodExtension())
1.154 + {
1.155 + if (m_PlId)
1.156 + {
1.157 + char dummy[255];
1.158 + g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
1.159 + m_PlId = 0;
1.160 + }
1.161 + }
1.162 + m_pLib->CloseLibrary();
1.163 + m_pLib = NULL;
1.164 + m_pAPI = NULL;
1.165 + return false;
1.166 + }
1.167 +
1.168 + return true;
1.169 +}
1.170 +
1.171 +void CRemoteExtension::Unload()
1.172 +{
1.173 +}
1.174 +
1.175 +void CLocalExtension::Unload()
1.176 +{
1.177 + if (m_pAPI != NULL && m_PlId)
1.178 + {
1.179 + char temp_buffer[255];
1.180 + g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
1.181 + m_PlId = 0;
1.182 + }
1.183 +
1.184 + if (m_pLib != NULL)
1.185 + {
1.186 + m_pLib->CloseLibrary();
1.187 + m_pLib = NULL;
1.188 + }
1.189 +}
1.190 +
1.191 +bool CRemoteExtension::IsExternal()
1.192 +{
1.193 + return true;
1.194 +}
1.195 +
1.196 +bool CLocalExtension::IsExternal()
1.197 +{
1.198 + return false;
1.199 +}
1.200 +
1.201 +CExtension::~CExtension()
1.202 +{
1.203 + DestroyIdentity();
1.204 +}
1.205 +
1.206 +bool CExtension::PerformAPICheck(char *error, size_t maxlength)
1.207 +{
1.208 + if (!m_pAPI)
1.209 + {
1.210 + snprintf(error, maxlength, "No IExtensionInterface instance provided");
1.211 + return false;
1.212 + }
1.213 +
1.214 + if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
1.215 + {
1.216 + snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
1.217 + return false;
1.218 + }
1.219 +
1.220 + return true;
1.221 +}
1.222 +
1.223 +bool CExtension::Load(char *error, size_t maxlength)
1.224 +{
1.225 + CreateIdentity();
1.226 + if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
1.227 + {
1.228 + DestroyIdentity();
1.229 + return false;
1.230 + }
1.231 + else
1.232 + {
1.233 + /* Check if we're past load time */
1.234 + if (!g_SourceMod.IsMapLoading())
1.235 + {
1.236 + m_pAPI->OnExtensionsAllLoaded();
1.237 + }
1.238 + }
1.239 +
1.240 + return true;
1.241 +}
1.242 +
1.243 +void CExtension::CreateIdentity()
1.244 +{
1.245 + if (m_pIdentToken != NULL)
1.246 + {
1.247 + return;
1.248 + }
1.249 +
1.250 + m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
1.251 +}
1.252 +
1.253 +void CExtension::DestroyIdentity()
1.254 +{
1.255 + if (m_pIdentToken == NULL)
1.256 + {
1.257 + return;
1.258 + }
1.259 +
1.260 + g_ShareSys.DestroyIdentity(m_pIdentToken);
1.261 + m_pIdentToken = NULL;
1.262 +}
1.263 +
1.264 +void CExtension::MarkAllLoaded()
1.265 +{
1.266 + assert(m_bFullyLoaded == false);
1.267 + if (!m_bFullyLoaded)
1.268 + {
1.269 + m_bFullyLoaded = true;
1.270 + m_pAPI->OnExtensionsAllLoaded();
1.271 + }
1.272 +}
1.273 +
1.274 +void CExtension::AddPlugin(CPlugin *pPlugin)
1.275 +{
1.276 + /* Unfortunately we have to do this :( */
1.277 + if (m_Dependents.find(pPlugin) != m_Dependents.end())
1.278 + {
1.279 + m_Dependents.push_back(pPlugin);
1.280 + }
1.281 +}
1.282 +
1.283 +void CExtension::SetError(const char *error)
1.284 +{
1.285 + m_Error.assign(error);
1.286 +}
1.287 +
1.288 +IExtensionInterface *CExtension::GetAPI()
1.289 +{
1.290 + return m_pAPI;
1.291 +}
1.292 +
1.293 +const char *CExtension::GetFilename()
1.294 +{
1.295 + return m_File.c_str();
1.296 +}
1.297 +
1.298 +IdentityToken_t *CExtension::GetIdentity()
1.299 +{
1.300 + return m_pIdentToken;
1.301 +}
1.302 +
1.303 +bool CRemoteExtension::IsLoaded()
1.304 +{
1.305 + return (m_pAPI != NULL);
1.306 +}
1.307 +
1.308 +bool CLocalExtension::IsLoaded()
1.309 +{
1.310 + return (m_pLib != NULL);
1.311 +}
1.312 +
1.313 +void CExtension::AddDependency(const IfaceInfo *pInfo)
1.314 +{
1.315 + if (m_Deps.find(*pInfo) == m_Deps.end())
1.316 + {
1.317 + m_Deps.push_back(*pInfo);
1.318 + }
1.319 +}
1.320 +
1.321 +bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
1.322 +{
1.323 + return (i1.iface == i2.iface) && (i1.owner == i2.owner);
1.324 +}
1.325 +
1.326 +void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
1.327 +{
1.328 + IfaceInfo info;
1.329 + info.iface = iface;
1.330 + info.owner = pOther;
1.331 +
1.332 + List<IfaceInfo>::iterator iter;
1.333 + for (iter = m_ChildDeps.begin();
1.334 + iter != m_ChildDeps.end();
1.335 + iter++)
1.336 + {
1.337 + IfaceInfo &other = (*iter);
1.338 + if (other == info)
1.339 + {
1.340 + return;
1.341 + }
1.342 + }
1.343 +
1.344 + m_ChildDeps.push_back(info);
1.345 +}
1.346 +
1.347 +ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
1.348 +{
1.349 + List<IfaceInfo>::iterator iter = m_Deps.begin();
1.350 +
1.351 + if (iter == m_Deps.end())
1.352 + {
1.353 + return NULL;
1.354 + }
1.355 +
1.356 + if (pOwner)
1.357 + {
1.358 + *pOwner = (*iter).owner;
1.359 + }
1.360 + if (pInterface)
1.361 + {
1.362 + *pInterface = (*iter).iface;
1.363 + }
1.364 +
1.365 + List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
1.366 +
1.367 + return (ITERATOR *)pIter;
1.368 +}
1.369 +
1.370 +bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
1.371 +{
1.372 + List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
1.373 + List<IfaceInfo>::iterator _iter;
1.374 +
1.375 + if (_iter == m_Deps.end())
1.376 + {
1.377 + return false;
1.378 + }
1.379 +
1.380 + _iter++;
1.381 +
1.382 + if (pOwner)
1.383 + {
1.384 + *pOwner = (*_iter).owner;
1.385 + }
1.386 + if (pInterface)
1.387 + {
1.388 + *pInterface = (*_iter).iface;
1.389 + }
1.390 +
1.391 + *pIter = _iter;
1.392 +
1.393 + if (_iter == m_Deps.end())
1.394 + {
1.395 + return false;
1.396 + }
1.397 +
1.398 + return true;
1.399 +}
1.400 +
1.401 +void CExtension::FreeDependencyIterator(ITERATOR *iter)
1.402 +{
1.403 + List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
1.404 +
1.405 + delete pIter;
1.406 +}
1.407 +
1.408 +void CExtension::AddInterface(SMInterface *pInterface)
1.409 +{
1.410 + m_Interfaces.push_back(pInterface);
1.411 +}
1.412 +
1.413 +bool CExtension::IsRunning(char *error, size_t maxlength)
1.414 +{
1.415 + if (!IsLoaded())
1.416 + {
1.417 + if (error)
1.418 + {
1.419 + snprintf(error, maxlength, "%s", m_Error.c_str());
1.420 + }
1.421 + return false;
1.422 + }
1.423 +
1.424 + return m_pAPI->QueryRunning(error, maxlength);
1.425 +}
1.426 +
1.427 +void CExtension::AddLibrary(const char *library)
1.428 +{
1.429 + m_Libraries.push_back(library);
1.430 +}
1.431 +
1.432 +/*********************
1.433 + * EXTENSION MANAGER *
1.434 + *********************/
1.435 +
1.436 +void CExtensionManager::OnSourceModAllInitialized()
1.437 +{
1.438 + g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
1.439 + g_PluginSys.AddPluginsListener(this);
1.440 + g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
1.441 + g_ShareSys.AddInterface(NULL, this);
1.442 +}
1.443 +
1.444 +void CExtensionManager::OnSourceModShutdown()
1.445 +{
1.446 + g_RootMenu.RemoveRootConsoleCommand("exts", this);
1.447 + g_ShareSys.DestroyIdentType(g_ExtType);
1.448 +}
1.449 +
1.450 +void CExtensionManager::Shutdown()
1.451 +{
1.452 + List<CExtension *>::iterator iter;
1.453 +
1.454 + while ((iter = m_Libs.begin()) != m_Libs.end())
1.455 + {
1.456 + UnloadExtension((*iter));
1.457 + }
1.458 +}
1.459 +
1.460 +void CExtensionManager::TryAutoload()
1.461 +{
1.462 + char path[PLATFORM_MAX_PATH];
1.463 +
1.464 + g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
1.465 +
1.466 + IDirectory *pDir = g_LibSys.OpenDirectory(path);
1.467 + if (!pDir)
1.468 + {
1.469 + return;
1.470 + }
1.471 +
1.472 + const char *lfile;
1.473 + size_t len;
1.474 + while (pDir->MoreFiles())
1.475 + {
1.476 + if (pDir->IsEntryDirectory())
1.477 + {
1.478 + pDir->NextEntry();
1.479 + continue;
1.480 + }
1.481 +
1.482 + lfile = pDir->GetEntryName();
1.483 + len = strlen(lfile);
1.484 + if (len <= 9) /* size of ".autoload" */
1.485 + {
1.486 + pDir->NextEntry();
1.487 + continue;
1.488 + }
1.489 +
1.490 + if (strcmp(&lfile[len - 9], ".autoload") != 0)
1.491 + {
1.492 + pDir->NextEntry();
1.493 + continue;
1.494 + }
1.495 +
1.496 + char file[PLATFORM_MAX_PATH];
1.497 + len = UTIL_Format(file, sizeof(file), "%s", lfile);
1.498 + strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
1.499 +
1.500 + LoadAutoExtension(file);
1.501 +
1.502 + pDir->NextEntry();
1.503 + }
1.504 +}
1.505 +
1.506 +IExtension *CExtensionManager::LoadAutoExtension(const char *path)
1.507 +{
1.508 + if (!strstr(path, "." PLATFORM_LIB_EXT))
1.509 + {
1.510 + char newpath[PLATFORM_MAX_PATH];
1.511 + g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
1.512 + return LoadAutoExtension(newpath);
1.513 + }
1.514 +
1.515 + IExtension *pAlready;
1.516 + if ((pAlready=FindExtensionByFile(path)) != NULL)
1.517 + {
1.518 + return pAlready;
1.519 + }
1.520 +
1.521 + char error[256];
1.522 + CExtension *p = new CLocalExtension(path);
1.523 +
1.524 + /* We put us in the list beforehand so extensions that check for each other
1.525 + * won't recursively load each other.
1.526 + */
1.527 + m_Libs.push_back(p);
1.528 +
1.529 + if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
1.530 + {
1.531 + g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
1.532 + p->SetError(error);
1.533 + }
1.534 +
1.535 + return p;
1.536 +}
1.537 +
1.538 +IExtension *CExtensionManager::FindExtensionByFile(const char *file)
1.539 +{
1.540 + List<CExtension *>::iterator iter;
1.541 + CExtension *pExt;
1.542 +
1.543 + /* Chomp off the path */
1.544 + char lookup[PLATFORM_MAX_PATH];
1.545 + g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
1.546 +
1.547 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.548 + {
1.549 + pExt = (*iter);
1.550 + char short_file[PLATFORM_MAX_PATH];
1.551 + g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
1.552 + if (strcmp(lookup, short_file) == 0)
1.553 + {
1.554 + return pExt;
1.555 + }
1.556 + }
1.557 +
1.558 + /* If we got no results, test if there was a platform extension.
1.559 + * If not, add one.
1.560 + */
1.561 + if (!strstr(file, "." PLATFORM_LIB_EXT))
1.562 + {
1.563 + char path[PLATFORM_MAX_PATH];
1.564 + UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
1.565 + return FindExtensionByFile(path);
1.566 + }
1.567 +
1.568 + return NULL;
1.569 +}
1.570 +
1.571 +IExtension *CExtensionManager::FindExtensionByName(const char *ext)
1.572 +{
1.573 + List<CExtension *>::iterator iter;
1.574 + CExtension *pExt;
1.575 + IExtensionInterface *pAPI;
1.576 + const char *name;
1.577 +
1.578 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.579 + {
1.580 + pExt = (*iter);
1.581 + if (!pExt->IsLoaded())
1.582 + {
1.583 + continue;
1.584 + }
1.585 + if ((pAPI = pExt->GetAPI()) == NULL)
1.586 + {
1.587 + continue;
1.588 + }
1.589 + name = pAPI->GetExtensionName();
1.590 + if (!name)
1.591 + {
1.592 + continue;
1.593 + }
1.594 + if (strcmp(name, ext) == 0)
1.595 + {
1.596 + return pExt;
1.597 + }
1.598 + }
1.599 +
1.600 + return NULL;
1.601 +}
1.602 +
1.603 +IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
1.604 +{
1.605 + IExtension *pAlready;
1.606 + if ((pAlready=FindExtensionByFile(file)) != NULL)
1.607 + {
1.608 + return pAlready;
1.609 + }
1.610 +
1.611 + CExtension *pExt = new CLocalExtension(file);
1.612 +
1.613 + if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
1.614 + {
1.615 + pExt->Unload();
1.616 + delete pExt;
1.617 + return NULL;
1.618 + }
1.619 +
1.620 + /* :TODO: do QueryRunning check if the map is loaded */
1.621 +
1.622 + m_Libs.push_back(pExt);
1.623 +
1.624 + return pExt;
1.625 +}
1.626 +
1.627 +void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
1.628 +{
1.629 + CExtension *pExt = (CExtension *)pRequester;
1.630 + CExtension *pOwner = (CExtension *)pInfo->owner;
1.631 +
1.632 + pExt->AddDependency(pInfo);
1.633 +
1.634 + IExtensionInterface *pAPI = pExt->GetAPI();
1.635 + if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
1.636 + {
1.637 + pOwner->AddChildDependent(pExt, pInfo->iface);
1.638 + }
1.639 +}
1.640 +
1.641 +void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface)
1.642 +{
1.643 + CExtension *pExt = (CExtension *)ext;
1.644 + CExtension *pOwner = GetExtensionFromIdent(other);
1.645 +
1.646 + IfaceInfo info;
1.647 +
1.648 + info.iface = (SMInterface *)iface;
1.649 + info.owner = pOwner;
1.650 +
1.651 + pExt->AddDependency(&info);
1.652 + pOwner->AddChildDependent(pExt, (SMInterface *)iface);
1.653 +}
1.654 +
1.655 +void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
1.656 +{
1.657 + CExtension *pExt = (CExtension *)pOwner;
1.658 +
1.659 + pExt->AddInterface(pInterface);
1.660 +}
1.661 +
1.662 +void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
1.663 +{
1.664 + CExtension *pExt = (CExtension *)pParent;
1.665 +
1.666 + pExt->AddPlugin(pPlugin);
1.667 +}
1.668 +
1.669 +void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
1.670 +{
1.671 + List<CExtension *>::iterator iter;
1.672 +
1.673 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.674 + {
1.675 + (*iter)->DropRefsTo((CPlugin *)plugin);
1.676 + }
1.677 +}
1.678 +
1.679 +CExtension *CExtensionManager::FindByOrder(unsigned int num)
1.680 +{
1.681 + if (num < 1 || num > m_Libs.size())
1.682 + {
1.683 + return NULL;
1.684 + }
1.685 +
1.686 + List<CExtension *>::iterator iter = m_Libs.begin();
1.687 +
1.688 + while (iter != m_Libs.end())
1.689 + {
1.690 + if (--num == 0)
1.691 + {
1.692 + return (*iter);
1.693 + }
1.694 + iter++;
1.695 + }
1.696 +
1.697 + return NULL;
1.698 +}
1.699 +
1.700 +bool CExtensionManager::UnloadExtension(IExtension *_pExt)
1.701 +{
1.702 + if (!_pExt)
1.703 + {
1.704 + return false;
1.705 + }
1.706 +
1.707 + CExtension *pExt = (CExtension *)_pExt;
1.708 +
1.709 + if (m_Libs.find(pExt) == m_Libs.end())
1.710 + {
1.711 + return false;
1.712 + }
1.713 +
1.714 + /* First remove us from internal lists */
1.715 + g_ShareSys.RemoveInterfaces(_pExt);
1.716 + m_Libs.remove(pExt);
1.717 +
1.718 + List<CExtension *> UnloadQueue;
1.719 +
1.720 + /* Handle dependencies */
1.721 + if (pExt->IsLoaded())
1.722 + {
1.723 + /* Unload any dependent plugins */
1.724 + List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
1.725 + while (p_iter != pExt->m_Dependents.end())
1.726 + {
1.727 + /* We have to manually unlink ourselves here, since we're no longer being managed */
1.728 + g_PluginSys.UnloadPlugin((*p_iter));
1.729 + p_iter = pExt->m_Dependents.erase(p_iter);
1.730 + }
1.731 +
1.732 + List<String>::iterator s_iter;
1.733 + for (s_iter = pExt->m_Libraries.begin();
1.734 + s_iter != pExt->m_Libraries.end();
1.735 + s_iter++)
1.736 + {
1.737 + g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
1.738 + }
1.739 +
1.740 + /* Notify and/or unload all dependencies */
1.741 + List<CExtension *>::iterator c_iter;
1.742 + CExtension *pDep;
1.743 + IExtensionInterface *pAPI;
1.744 + for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
1.745 + {
1.746 + pDep = (*c_iter);
1.747 + if ((pAPI=pDep->GetAPI()) == NULL)
1.748 + {
1.749 + continue;
1.750 + }
1.751 + if (pDep == pExt)
1.752 + {
1.753 + continue;
1.754 + }
1.755 + /* Now, get its dependency list */
1.756 + bool dropped = false;
1.757 + List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
1.758 + while (i_iter != pDep->m_Deps.end())
1.759 + {
1.760 + if ((*i_iter).owner == _pExt)
1.761 + {
1.762 + if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
1.763 + {
1.764 + if (!dropped)
1.765 + {
1.766 + dropped = true;
1.767 + UnloadQueue.push_back(pDep);
1.768 + }
1.769 + }
1.770 + pAPI->NotifyInterfaceDrop((*i_iter).iface);
1.771 + i_iter = pDep->m_Deps.erase(i_iter);
1.772 + }
1.773 + else
1.774 + {
1.775 + i_iter++;
1.776 + }
1.777 + }
1.778 + /* Flush out any back references to this plugin */
1.779 + i_iter = pDep->m_ChildDeps.begin();
1.780 + while (i_iter != pDep->m_ChildDeps.end())
1.781 + {
1.782 + if ((*i_iter).owner == pExt)
1.783 + {
1.784 + i_iter = pDep->m_ChildDeps.erase(i_iter);
1.785 + }
1.786 + else
1.787 + {
1.788 + i_iter++;
1.789 + }
1.790 + }
1.791 + }
1.792 +
1.793 + /* Unbind our natives from Core */
1.794 + pExt->DropEverything();
1.795 + }
1.796 +
1.797 + IdentityToken_t *pIdentity;
1.798 + if ((pIdentity = pExt->GetIdentity()) != NULL)
1.799 + {
1.800 + SMGlobalClass *glob = SMGlobalClass::head;
1.801 + while (glob)
1.802 + {
1.803 + glob->OnSourceModIdentityDropped(pIdentity);
1.804 + glob = glob->m_pGlobalClassNext;
1.805 + }
1.806 + }
1.807 +
1.808 + /* Tell it to unload */
1.809 + if (pExt->IsLoaded())
1.810 + {
1.811 + IExtensionInterface *pAPI = pExt->GetAPI();
1.812 + pAPI->OnExtensionUnload();
1.813 + }
1.814 +
1.815 + pExt->Unload();
1.816 + delete pExt;
1.817 +
1.818 + List<CExtension *>::iterator iter;
1.819 + for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
1.820 + {
1.821 + /* NOTE: This is safe because the unload function backs out of anything not present */
1.822 + UnloadExtension((*iter));
1.823 + }
1.824 +
1.825 + return true;
1.826 +}
1.827 +
1.828 +void CExtensionManager::MarkAllLoaded()
1.829 +{
1.830 + List<CExtension *>::iterator iter;
1.831 + CExtension *pExt;
1.832 +
1.833 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.834 + {
1.835 + pExt = (*iter);
1.836 + if (!pExt->IsLoaded())
1.837 + {
1.838 + continue;
1.839 + }
1.840 + if (pExt->m_bFullyLoaded)
1.841 + {
1.842 + continue;
1.843 + }
1.844 + pExt->MarkAllLoaded();
1.845 + }
1.846 +}
1.847 +
1.848 +void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
1.849 +{
1.850 + /* This function doesn't really need to do anything now. We make sure the
1.851 + * other extension is loaded, but handling of dependencies is really done
1.852 + * by the interface fetcher.
1.853 + */
1.854 + if (required || autoload)
1.855 + {
1.856 + LoadAutoExtension(file);
1.857 + }
1.858 +}
1.859 +
1.860 +void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
1.861 +{
1.862 + int argcount = command.ArgC();
1.863 + if (argcount >= 3)
1.864 + {
1.865 + const char *cmd = command.Arg(2);
1.866 + if (strcmp(cmd, "list") == 0)
1.867 + {
1.868 + List<CExtension *>::iterator iter;
1.869 + CExtension *pExt;
1.870 + unsigned int num = 1;
1.871 + switch (m_Libs.size())
1.872 + {
1.873 + case 1:
1.874 + {
1.875 + g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
1.876 + break;
1.877 + }
1.878 + case 0:
1.879 + {
1.880 + g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
1.881 + break;
1.882 + }
1.883 + default:
1.884 + {
1.885 + g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
1.886 + break;
1.887 + }
1.888 + }
1.889 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
1.890 + {
1.891 + pExt = (*iter);
1.892 + if (pExt->IsLoaded())
1.893 + {
1.894 + char error[255];
1.895 + if (!pExt->IsRunning(error, sizeof(error)))
1.896 + {
1.897 + g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
1.898 + }
1.899 + else
1.900 + {
1.901 + IExtensionInterface *pAPI = pExt->GetAPI();
1.902 + const char *name = pAPI->GetExtensionName();
1.903 + const char *version = pAPI->GetExtensionVerString();
1.904 + const char *descr = pAPI->GetExtensionDescription();
1.905 + g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
1.906 + }
1.907 + } else {
1.908 + g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
1.909 + }
1.910 + }
1.911 + return;
1.912 + }
1.913 + else if (strcmp(cmd, "info") == 0)
1.914 + {
1.915 + if (argcount < 4)
1.916 + {
1.917 + g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
1.918 + return;
1.919 + }
1.920 +
1.921 + const char *sId = command.Arg(3);
1.922 + unsigned int id = atoi(sId);
1.923 + if (id <= 0)
1.924 + {
1.925 + g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
1.926 + return;
1.927 + }
1.928 +
1.929 + if (m_Libs.size() == 0)
1.930 + {
1.931 + g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
1.932 + return;
1.933 + }
1.934 +
1.935 + if (id > m_Libs.size())
1.936 + {
1.937 + g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
1.938 + return;
1.939 + }
1.940 +
1.941 + List<CExtension *>::iterator iter = m_Libs.begin();
1.942 + CExtension *pExt = NULL;
1.943 + while (iter != m_Libs.end())
1.944 + {
1.945 + if (--id == 0)
1.946 + {
1.947 + pExt = (*iter);
1.948 + break;
1.949 + }
1.950 + iter++;
1.951 + }
1.952 + /* This should never happen */
1.953 + if (!pExt)
1.954 + {
1.955 + g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
1.956 + return;
1.957 + }
1.958 +
1.959 + if (!pExt->IsLoaded())
1.960 + {
1.961 + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.962 + g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
1.963 + }
1.964 + else
1.965 + {
1.966 + char error[255];
1.967 + if (!pExt->IsRunning(error, sizeof(error)))
1.968 + {
1.969 + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.970 + g_RootMenu.ConsolePrint(" Loaded: Yes");
1.971 + g_RootMenu.ConsolePrint(" Running: No (%s)", error);
1.972 + }
1.973 + else
1.974 + {
1.975 + IExtensionInterface *pAPI = pExt->GetAPI();
1.976 + g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.977 + g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
1.978 + g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
1.979 + g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
1.980 + g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
1.981 +
1.982 + if (pExt->IsExternal())
1.983 + {
1.984 + g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
1.985 + }
1.986 + else if (pAPI->IsMetamodExtension())
1.987 + {
1.988 + g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
1.989 + }
1.990 + else
1.991 + {
1.992 + g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
1.993 + }
1.994 + }
1.995 + }
1.996 + return;
1.997 + }
1.998 + else if (strcmp(cmd, "unload") == 0)
1.999 + {
1.1000 + if (argcount < 4)
1.1001 + {
1.1002 + g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
1.1003 + return;
1.1004 + }
1.1005 +
1.1006 + const char *arg = command.Arg(3);
1.1007 + unsigned int num = atoi(arg);
1.1008 + CExtension *pExt = FindByOrder(num);
1.1009 +
1.1010 + if (!pExt)
1.1011 + {
1.1012 + g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
1.1013 + return;
1.1014 + }
1.1015 +
1.1016 + if (argcount > 4 && pExt->unload_code)
1.1017 + {
1.1018 + const char *unload = command.Arg(4);
1.1019 + if (pExt->unload_code == (unsigned)atoi(unload))
1.1020 + {
1.1021 + char filename[PLATFORM_MAX_PATH];
1.1022 + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
1.1023 + UnloadExtension(pExt);
1.1024 + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
1.1025 + }
1.1026 + else
1.1027 + {
1.1028 + g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
1.1029 + }
1.1030 + return;
1.1031 + }
1.1032 +
1.1033 + if (!pExt->IsLoaded()
1.1034 + || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
1.1035 + {
1.1036 + char filename[PLATFORM_MAX_PATH];
1.1037 + snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
1.1038 + UnloadExtension(pExt);
1.1039 + g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
1.1040 + return;
1.1041 + }
1.1042 + else
1.1043 + {
1.1044 + List<CPlugin *> plugins;
1.1045 + if (pExt->m_ChildDeps.size())
1.1046 + {
1.1047 + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
1.1048 + List<CExtension *>::iterator iter;
1.1049 + CExtension *pOther;
1.1050 + /* Get list of all extensions */
1.1051 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.1052 + {
1.1053 + List<IfaceInfo>::iterator i_iter;
1.1054 + pOther = (*iter);
1.1055 + if (!pOther->IsLoaded() || pOther == pExt)
1.1056 + {
1.1057 + continue;
1.1058 + }
1.1059 + /* Get their dependencies */
1.1060 + for (i_iter=pOther->m_Deps.begin();
1.1061 + i_iter!=pOther->m_Deps.end();
1.1062 + i_iter++)
1.1063 + {
1.1064 + /* Is this dependency to us? */
1.1065 + if ((*i_iter).owner != pExt)
1.1066 + {
1.1067 + continue;
1.1068 + }
1.1069 + /* Will our dependent care? */
1.1070 + if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
1.1071 + {
1.1072 + g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
1.1073 + /* Add to plugin unload list */
1.1074 + List<CPlugin *>::iterator p_iter;
1.1075 + for (p_iter=pOther->m_Dependents.begin();
1.1076 + p_iter!=pOther->m_Dependents.end();
1.1077 + p_iter++)
1.1078 + {
1.1079 + if (plugins.find((*p_iter)) == plugins.end())
1.1080 + {
1.1081 + plugins.push_back((*p_iter));
1.1082 + }
1.1083 + }
1.1084 + }
1.1085 + }
1.1086 + }
1.1087 + }
1.1088 + if (pExt->m_Dependents.size())
1.1089 + {
1.1090 + g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
1.1091 + List<CPlugin *>::iterator iter;
1.1092 + CPlugin *pPlugin;
1.1093 + for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
1.1094 + {
1.1095 + pPlugin = (*iter);
1.1096 + if (plugins.find(pPlugin) == plugins.end())
1.1097 + {
1.1098 + plugins.push_back(pPlugin);
1.1099 + }
1.1100 + }
1.1101 + for (iter = plugins.begin(); iter != plugins.end(); iter++)
1.1102 + {
1.1103 + pPlugin = (*iter);
1.1104 + g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
1.1105 + }
1.1106 + }
1.1107 + srand(static_cast<int>(time(NULL)));
1.1108 + pExt->unload_code = (rand() % 877) + 123; //123 to 999
1.1109 + g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
1.1110 + g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
1.1111 +
1.1112 + return;
1.1113 + }
1.1114 + }
1.1115 + }
1.1116 +
1.1117 + g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
1.1118 + g_RootMenu.DrawGenericOption("info", "Extra extension information");
1.1119 + g_RootMenu.DrawGenericOption("list", "List extensions");
1.1120 + g_RootMenu.DrawGenericOption("unload", "Unload an extension");
1.1121 +}
1.1122 +
1.1123 +CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
1.1124 +{
1.1125 + if (ptr->type == g_ExtType)
1.1126 + {
1.1127 + return (CExtension *)(ptr->ptr);
1.1128 + }
1.1129 +
1.1130 + return NULL;
1.1131 +}
1.1132 +
1.1133 +CExtensionManager::CExtensionManager()
1.1134 +{
1.1135 +}
1.1136 +
1.1137 +CExtensionManager::~CExtensionManager()
1.1138 +{
1.1139 +}
1.1140 +
1.1141 +void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
1.1142 +{
1.1143 + CExtension *pExt = (CExtension *)pSource;
1.1144 + pExt->AddLibrary(library);
1.1145 + g_PluginSys.OnLibraryAction(library, false, false);
1.1146 +}
1.1147 +
1.1148 +bool CExtensionManager::LibraryExists(const char *library)
1.1149 +{
1.1150 + CExtension *pExt;
1.1151 +
1.1152 + for (List<CExtension *>::iterator iter = m_Libs.begin();
1.1153 + iter != m_Libs.end();
1.1154 + iter++)
1.1155 + {
1.1156 + pExt = (*iter);
1.1157 + for (List<String>::iterator s_iter = pExt->m_Libraries.begin();
1.1158 + s_iter != pExt->m_Libraries.end();
1.1159 + s_iter++)
1.1160 + {
1.1161 + if ((*s_iter).compare(library) == 0)
1.1162 + {
1.1163 + return true;
1.1164 + }
1.1165 + }
1.1166 + }
1.1167 +
1.1168 + return false;
1.1169 +}
1.1170 +
1.1171 +IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
1.1172 + const char *filepath,
1.1173 + const char *filename,
1.1174 + char *error,
1.1175 + size_t maxlength)
1.1176 +{
1.1177 + IExtension *pAlready;
1.1178 + if ((pAlready=FindExtensionByFile(filename)) != NULL)
1.1179 + {
1.1180 + return pAlready;
1.1181 + }
1.1182 +
1.1183 + CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
1.1184 +
1.1185 + if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
1.1186 + {
1.1187 + pExt->Unload();
1.1188 + delete pExt;
1.1189 + return NULL;
1.1190 + }
1.1191 +
1.1192 + m_Libs.push_back(pExt);
1.1193 +
1.1194 + return pExt;
1.1195 +}
1.1196 +
1.1197 +void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
1.1198 +{
1.1199 + IExtensionInterface *pAPI;
1.1200 + List<CExtension *>::iterator iter;
1.1201 +
1.1202 + for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1.1203 + {
1.1204 + if ((pAPI = (*iter)->GetAPI()) == NULL)
1.1205 + {
1.1206 + continue;
1.1207 + }
1.1208 + if (pAPI->GetExtensionVersion() > 3)
1.1209 + {
1.1210 + pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);
1.1211 + }
1.1212 + }
1.1213 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/core/ExtensionSys.h Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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(¶m->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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:14:43 2008 -0600
9.2 +++ b/core/Logger.cpp Wed Nov 19 02:16:45 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 Wed Nov 19 02:14:43 2008 -0600
10.2 +++ b/core/Makefile Wed Nov 19 02:16:45 2008 -0600
10.3 @@ -28,9 +28,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 Wed Nov 19 02:14:43 2008 -0600
11.2 +++ b/core/PlayerManager.cpp Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 2008 -0600
15.3 @@ -0,0 +1,460 @@
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 SOURCE_ENGINE == SE_LEFT4DEAD
15.54 +#include "convar_sm_l4d.h"
15.55 +#elif SOURCE_ENGINE == SE_ORANGEBOX
15.56 +#include "convar_sm_ob.h"
15.57 +#else
15.58 +#include "convar_sm.h"
15.59 +#endif
15.60 +#include "ITranslator.h"
15.61 +#include "NativeOwner.h"
15.62 +#include "ShareSys.h"
15.63 +
15.64 +using namespace SourceHook;
15.65 +
15.66 +/**
15.67 + * NOTES:
15.68 + *
15.69 + * UPDATE 2008-03-11: These comments are horribly out of date. They paint a good overall
15.70 + * picture of how PluginSys works, but things like dependencies and fake natives have
15.71 + * complicated things quite a bit.
15.72 + *
15.73 + * Currently this system needs a lot of work but it's good skeletally. Plugin creation
15.74 + * is done without actually compiling anything. This is done by Load functions in the
15.75 + * manager. This will need a rewrite when we add context switching.
15.76 + *
15.77 + * The plugin object itself has a few things to note. The most important is that it stores
15.78 + * a table of function objects. The manager marshals allocation and freeing of these objects.
15.79 + * The plugin object can be in erroneous states, they are:
15.80 + * Plugin_Error --> Some error occurred any time during or after compilation.
15.81 + * This error can be cleared since the plugin itself is valid.
15.82 + * However, the state itself being set prevents any runtime action.
15.83 + * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
15.84 + *
15.85 + * If a plugin fails to load externally, it is never added to the internal tracker. However,
15.86 + * plugins that failed to load from the internal loading mechanism are always tracked. This
15.87 + * allows users to see which automatically loaded plugins failed, and makes the interface a bit
15.88 + * more flexible.
15.89 + *
15.90 + * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
15.91 + * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
15.92 + * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
15.93 + * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
15.94 + *
15.95 + * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
15.96 + * PASS ONE: All loadable plugins are found and have the following steps performed:
15.97 + * 1. Loading and compilation is attempted.
15.98 + * 2. If successful, all natives from Core are added.
15.99 + * 3. OnPluginLoad() is called.
15.100 + * 4. If failed, any user natives are scrapped and the process halts here.
15.101 + * 5. If successful, the plugin is ready for Pass 2.
15.102 + * INTERMEDIATE:
15.103 + * 1. All forced modules are loaded.
15.104 + * PASS TWO: All loaded plugins are found and have these steps performed:
15.105 + * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
15.106 + * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
15.107 + * 3. If any natives are unresolved, check if they are found in the user-natives pool.
15.108 + * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
15.109 + * 5. If the filter fails, the plugin is marked as failed.
15.110 + * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
15.111 + * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
15.112 + * PASS THREE (not a real pass):
15.113 + * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
15.114 + */
15.115 +
15.116 +enum LoadRes
15.117 +{
15.118 + LoadRes_Successful,
15.119 + LoadRes_AlreadyLoaded,
15.120 + LoadRes_Failure,
15.121 + LoadRes_NeverLoad
15.122 +};
15.123 +
15.124 +struct AutoConfig
15.125 +{
15.126 + String autocfg;
15.127 + String folder;
15.128 + bool create;
15.129 +};
15.130 +
15.131 +class CPlugin;
15.132 +
15.133 +class CPlugin :
15.134 + public IPlugin,
15.135 + public CNativeOwner
15.136 +{
15.137 + friend class CPluginManager;
15.138 + friend class CFunction;
15.139 +public:
15.140 + CPlugin(const char *file);
15.141 + ~CPlugin();
15.142 +public:
15.143 + PluginType GetType();
15.144 + SourcePawn::IPluginContext *GetBaseContext();
15.145 + sp_context_t *GetContext();
15.146 + void *GetPluginStructure();
15.147 + const char *GetFilename();
15.148 + bool IsDebugging();
15.149 + PluginStatus GetStatus();
15.150 + const sm_plugininfo_t *GetPublicInfo();
15.151 + bool SetPauseState(bool paused);
15.152 + unsigned int GetSerial();
15.153 + IdentityToken_t *GetIdentity();
15.154 + unsigned int CalcMemUsage();
15.155 + bool SetProperty(const char *prop, void *ptr);
15.156 + bool GetProperty(const char *prop, void **ptr, bool remove=false);
15.157 + void DropEverything();
15.158 + SourcePawn::IPluginRuntime *GetRuntime();
15.159 +public:
15.160 + /**
15.161 + * Creates a plugin object with default values.
15.162 + * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
15.163 + * and NULL will be returned.
15.164 + * If an error buffer is not specified, the error will be copied to an internal buffer and
15.165 + * a valid (but error-stated) CPlugin will be returned.
15.166 + */
15.167 + static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
15.168 +public:
15.169 +
15.170 + /**
15.171 + * Sets an error state on the plugin
15.172 + */
15.173 + void SetErrorState(PluginStatus status, const char *error_fmt, ...);
15.174 +
15.175 + /**
15.176 + * Initializes the plugin's identity information
15.177 + */
15.178 + void InitIdentity();
15.179 +
15.180 + /**
15.181 + * Calls the OnPluginLoad function, and sets any failed states if necessary.
15.182 + * NOTE: Valid pre-states are: Plugin_Created
15.183 + * NOTE: If validated, plugin state is changed to Plugin_Loaded
15.184 + *
15.185 + * If the error buffer is NULL, the error message is cached locally.
15.186 + */
15.187 + bool Call_AskPluginLoad(char *error, size_t maxlength);
15.188 +
15.189 + /**
15.190 + * Calls the OnPluginStart function.
15.191 + * NOTE: Valid pre-states are: Plugin_Created
15.192 + * NOTE: Post-state will be Plugin_Running
15.193 + */
15.194 + void Call_OnPluginStart();
15.195 +
15.196 + /**
15.197 + * Calls the OnPluginEnd function.
15.198 + */
15.199 + void Call_OnPluginEnd();
15.200 +
15.201 + /**
15.202 + * Calls the OnAllPluginsLoaded function.
15.203 + */
15.204 + void Call_OnAllPluginsLoaded();
15.205 +
15.206 + /**
15.207 + * Returns true if a plugin is usable.
15.208 + */
15.209 + bool IsRunnable();
15.210 +
15.211 + /**
15.212 + * Get languages info.
15.213 + */
15.214 + IPhraseCollection *GetPhrases();
15.215 +public:
15.216 + /**
15.217 + * Returns the modification time during last plugin load.
15.218 + */
15.219 + time_t GetTimeStamp();
15.220 +
15.221 + /**
15.222 + * Returns the current modification time of the plugin file.
15.223 + */
15.224 + time_t GetFileTimeStamp();
15.225 +
15.226 + /**
15.227 + * Returns true if the plugin was running, but is now invalid.
15.228 + */
15.229 + bool WasRunning();
15.230 +
15.231 + Handle_t GetMyHandle();
15.232 +
15.233 + bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
15.234 + void AddConfig(bool autoCreate, const char *cfg, const char *folder);
15.235 + unsigned int GetConfigCount();
15.236 + AutoConfig *GetConfig(unsigned int i);
15.237 + inline void AddLibrary(const char *name)
15.238 + {
15.239 + m_Libraries.push_back(name);
15.240 + }
15.241 + void LibraryActions(bool dropping);
15.242 + void SyncMaxClients(int max_clients);
15.243 +protected:
15.244 + bool UpdateInfo();
15.245 + void SetTimeStamp(time_t t);
15.246 + void DependencyDropped(CPlugin *pOwner);
15.247 +private:
15.248 + PluginType m_type;
15.249 + char m_filename[PLATFORM_MAX_PATH];
15.250 + PluginStatus m_status;
15.251 + unsigned int m_serial;
15.252 + sm_plugininfo_t m_info;
15.253 + char m_errormsg[256];
15.254 + time_t m_LastAccess;
15.255 + IdentityToken_t *m_ident;
15.256 + Handle_t m_handle;
15.257 + bool m_WasRunning;
15.258 + IPhraseCollection *m_pPhrases;
15.259 + List<String> m_RequiredLibs;
15.260 + List<String> m_Libraries;
15.261 + Trie *m_pProps;
15.262 + bool m_FakeNativesMissing;
15.263 + bool m_LibraryMissing;
15.264 + CVector<AutoConfig *> m_configs;
15.265 + bool m_bGotAllLoaded;
15.266 + int m_FileVersion;
15.267 + char m_DateTime[256];
15.268 + IPluginRuntime *m_pRuntime;
15.269 + IPluginContext *m_pContext;
15.270 + sp_pubvar_t *m_MaxClientsVar;
15.271 +};
15.272 +
15.273 +class CPluginManager :
15.274 + public IPluginManager,
15.275 + public SMGlobalClass,
15.276 + public IHandleTypeDispatch,
15.277 + public IRootConsoleCommand
15.278 +{
15.279 + friend class CPlugin;
15.280 +public:
15.281 + CPluginManager();
15.282 + ~CPluginManager();
15.283 +public:
15.284 + /* Implements iterator class */
15.285 + class CPluginIterator : public IPluginIterator
15.286 + {
15.287 + public:
15.288 + CPluginIterator(List<CPlugin *> *mylist);
15.289 + virtual ~CPluginIterator();
15.290 + virtual bool MorePlugins();
15.291 + virtual IPlugin *GetPlugin();
15.292 + virtual void NextPlugin();
15.293 + void Release();
15.294 + public:
15.295 + void Reset();
15.296 + private:
15.297 + List<CPlugin *> *mylist;
15.298 + List<CPlugin *>::iterator current;
15.299 + };
15.300 + friend class CPluginManager::CPluginIterator;
15.301 +public: //IPluginManager
15.302 + IPlugin *LoadPlugin(const char *path,
15.303 + bool debug,
15.304 + PluginType type,
15.305 + char error[],
15.306 + size_t maxlength,
15.307 + bool *wasloaded);
15.308 + bool UnloadPlugin(IPlugin *plugin);
15.309 + IPlugin *FindPluginByContext(const sp_context_t *ctx);
15.310 + unsigned int GetPluginCount();
15.311 + IPluginIterator *GetPluginIterator();
15.312 + void AddPluginsListener(IPluginsListener *listener);
15.313 + void RemovePluginsListener(IPluginsListener *listener);
15.314 +public: //SMGlobalClass
15.315 + void OnSourceModAllInitialized();
15.316 + void OnSourceModShutdown();
15.317 + void OnSourceModMaxPlayersChanged(int newvalue);
15.318 +public: //IHandleTypeDispatch
15.319 + void OnHandleDestroy(HandleType_t type, void *object);
15.320 + bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
15.321 +public: //IRootConsoleCommand
15.322 + void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
15.323 +public:
15.324 + /**
15.325 + * Loads all plugins not yet loaded
15.326 + */
15.327 + void LoadAll_FirstPass(const char *config, const char *basedir);
15.328 +
15.329 + /**
15.330 + * Runs the second loading pass for all plugins
15.331 + */
15.332 + void LoadAll_SecondPass();
15.333 +
15.334 + /**
15.335 + * Tests a plugin file mask against a local folder.
15.336 + * The alias is searched backwards from localdir - i.e., given this input:
15.337 + * csdm/ban csdm/ban
15.338 + * ban csdm/ban
15.339 + * csdm/ban optional/csdm/ban
15.340 + * All of these will return true for an alias match.
15.341 + * Wildcards are allowed in the filename.
15.342 + */
15.343 + bool TestAliasMatch(const char *alias, const char *localdir);
15.344 +
15.345 + /**
15.346 + * Returns whether anything loaded will be a late load.
15.347 + */
15.348 + bool IsLateLoadTime() const;
15.349 +
15.350 + /**
15.351 + * Converts a Handle to an IPlugin if possible.
15.352 + */
15.353 + IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
15.354 +
15.355 + /**
15.356 + * Finds a plugin based on its index. (starts on index 1)
15.357 + */
15.358 + CPlugin *GetPluginByOrder(int num);
15.359 +
15.360 + int GetOrderOfPlugin(IPlugin *pl);
15.361 +
15.362 + /**
15.363 + * Internal version of FindPluginByContext()
15.364 + */
15.365 + CPlugin *GetPluginByCtx(const sp_context_t *ctx);
15.366 +
15.367 + /**
15.368 + * Gets status text for a status code
15.369 + */
15.370 + const char *GetStatusText(PluginStatus status);
15.371 +
15.372 + /**
15.373 + * Reload or update plugins on level shutdown.
15.374 + */
15.375 + void ReloadOrUnloadPlugins();
15.376 +
15.377 + /**
15.378 + * Add public functions from all running or paused
15.379 + * plugins to the specified forward if the names match.
15.380 + */
15.381 + void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
15.382 +
15.383 + /**
15.384 + * Iterates through plugins to call OnAllPluginsLoaded.
15.385 + */
15.386 + void AllPluginsLoaded();
15.387 +
15.388 + CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
15.389 +
15.390 + void Shutdown();
15.391 +
15.392 + void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
15.393 +
15.394 + bool LibraryExists(const char *lib);
15.395 +
15.396 + bool ReloadPlugin(CPlugin *pl);
15.397 +
15.398 + void UnloadAll();
15.399 +
15.400 + CPlugin *FindPluginByConsoleArg(const char *arg);
15.401 +
15.402 + void SyncMaxClients(int max_clients);
15.403 +private:
15.404 + LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
15.405 +
15.406 + void LoadAutoPlugin(const char *plugin);
15.407 +
15.408 + /**
15.409 + * Recursively loads all plugins in the given directory.
15.410 + */
15.411 + void LoadPluginsFromDir(const char *basedir, const char *localdir);
15.412 +
15.413 + /**
15.414 + * Adds a plugin object. This is wrapped by LoadPlugin functions.
15.415 + */
15.416 + void AddPlugin(CPlugin *pPlugin);
15.417 +
15.418 + /**
15.419 + * Runs the second loading pass on a plugin.
15.420 + */
15.421 + bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
15.422 +
15.423 + /**
15.424 + * Runs an extension pass on a plugin.
15.425 + */
15.426 + bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
15.427 +
15.428 + /**
15.429 + * Manages required natives.
15.430 + */
15.431 + bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
15.432 +
15.433 + void _SetPauseState(CPlugin *pPlugin, bool pause);
15.434 +protected:
15.435 + /**
15.436 + * Caching internal objects
15.437 + */
15.438 + void ReleaseIterator(CPluginIterator *iter);
15.439 +public:
15.440 + inline IdentityToken_t *GetIdentity()
15.441 + {
15.442 + return m_MyIdent;
15.443 + }
15.444 +private:
15.445 + void TryRefreshDependencies(CPlugin *pOther);
15.446 +private:
15.447 + List<IPluginsListener *> m_listeners;
15.448 + List<CPlugin *> m_plugins;
15.449 + CStack<CPluginManager::CPluginIterator *> m_iters;
15.450 + CPluginInfoDatabase m_PluginInfo;
15.451 + Trie *m_LoadLookup;
15.452 + bool m_AllPluginsLoaded;
15.453 + IdentityToken_t *m_MyIdent;
15.454 +
15.455 + /* Dynamic native stuff */
15.456 + List<FakeNative *> m_Natives;
15.457 +
15.458 + bool m_LoadingLocked;
15.459 +};
15.460 +
15.461 +extern CPluginManager g_PluginSys;
15.462 +
15.463 +#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/core/ShareSys.cpp Wed Nov 19 02:16:45 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 Wed Nov 19 02:16:45 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 Wed Nov 19 02:14:43 2008 -0600
18.2 +++ b/core/msvc8/sourcemod_mm.vcproj Wed Nov 19 02:16:45 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 Wed Nov 19 02:14:43 2008 -0600
19.2 +++ b/core/msvc9/sourcemod_mm.vcproj Wed Nov 19 02:16:45 2008 -0600
19.3 @@ -1102,6 +1102,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 @@ -1118,6 +1126,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 @@ -1166,10 +1182,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 @@ -1284,6 +1312,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 @@ -1300,6 +1336,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 @@ -1348,10 +1392,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 @@ -1522,79 +1578,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 Wed Nov 19 02:14:43 2008 -0600
20.2 +++ b/core/sourcemod.cpp Wed Nov 19 02:16:45 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 Wed Nov 19 02:14:43 2008 -0600
21.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
21.3 @@ -1,1210 +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 SOURCE_ENGINE == SE_LEFT4DEAD
21.76 - "extensions/auto.2.l4d/%s",
21.77 -#elif SOURCE_ENGINE == SE_ORANGEBOX
21.78 - "extensions/auto.2.ep2/%s",
21.79 -#else
21.80 - "extensions/auto.2.ep1/%s",
21.81 -#endif //SOURCE_ENGINE == SE_LEFT4DEAD
21.82 -#else //METAMOD_PLAPI_VERSION
21.83 - "extensions/auto.1.ep1/%s",
21.84 -#endif //METAMOD_PLAPI_VERSION
21.85 - filename);
21.86 -
21.87 - /* Try the "normal" version */
21.88 - if (!g_LibSys.IsPathFile(path))
21.89 - {
21.90 - g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
21.91 - }
21.92 -
21.93 - Initialize(filename, path);
21.94 -}
21.95 -
21.96 -bool CRemoteExtension::Load(char *error, size_t maxlength)
21.97 -{
21.98 - if (!PerformAPICheck(error, maxlength))
21.99 - {
21.100 - m_pAPI = NULL;
21.101 - return false;
21.102 - }
21.103 -
21.104 - if (!CExtension::Load(error, maxlength))
21.105 - {
21.106 - m_pAPI = NULL;
21.107 - return false;
21.108 - }
21.109 -
21.110 - return true;
21.111 -}
21.112 -
21.113 -bool CLocalExtension::Load(char *error, size_t maxlength)
21.114 -{
21.115 - m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
21.116 -
21.117 - if (m_pLib == NULL)
21.118 - {
21.119 - return false;
21.120 - }
21.121 -
21.122 - typedef IExtensionInterface *(*GETAPI)();
21.123 - GETAPI pfnGetAPI = NULL;
21.124 -
21.125 - if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
21.126 - {
21.127 - m_pLib->CloseLibrary();
21.128 - m_pLib = NULL;
21.129 - snprintf(error, maxlength, "Unable to find extension entry point");
21.130 - return false;
21.131 - }
21.132 -
21.133 - m_pAPI = pfnGetAPI();
21.134 -
21.135 - /* Check pointer and version */
21.136 - if (!PerformAPICheck(error, maxlength))
21.137 - {
21.138 - m_pLib->CloseLibrary();
21.139 - m_pLib = NULL;
21.140 - m_pAPI = NULL;
21.141 - return false;
21.142 - }
21.143 -
21.144 - /* Load as MM:S */
21.145 - if (m_pAPI->IsMetamodExtension())
21.146 - {
21.147 - bool already;
21.148 - m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
21.149 - }
21.150 -
21.151 - if (!CExtension::Load(error, maxlength))
21.152 - {
21.153 - if (m_pAPI->IsMetamodExtension())
21.154 - {
21.155 - if (m_PlId)
21.156 - {
21.157 - char dummy[255];
21.158 - g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
21.159 - m_PlId = 0;
21.160 - }
21.161 - }
21.162 - m_pLib->CloseLibrary();
21.163 - m_pLib = NULL;
21.164 - m_pAPI = NULL;
21.165 - return false;
21.166 - }
21.167 -
21.168 - return true;
21.169 -}
21.170 -
21.171 -void CRemoteExtension::Unload()
21.172 -{
21.173 -}
21.174 -
21.175 -void CLocalExtension::Unload()
21.176 -{
21.177 - if (m_pAPI != NULL && m_PlId)
21.178 - {
21.179 - char temp_buffer[255];
21.180 - g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
21.181 - m_PlId = 0;
21.182 - }
21.183 -
21.184 - if (m_pLib != NULL)
21.185 - {
21.186 - m_pLib->CloseLibrary();
21.187 - m_pLib = NULL;
21.188 - }
21.189 -}
21.190 -
21.191 -bool CRemoteExtension::IsExternal()
21.192 -{
21.193 - return true;
21.194 -}
21.195 -
21.196 -bool CLocalExtension::IsExternal()
21.197 -{
21.198 - return false;
21.199 -}
21.200 -
21.201 -CExtension::~CExtension()
21.202 -{
21.203 - DestroyIdentity();
21.204 -}
21.205 -
21.206 -bool CExtension::PerformAPICheck(char *error, size_t maxlength)
21.207 -{
21.208 - if (!m_pAPI)
21.209 - {
21.210 - snprintf(error, maxlength, "No IExtensionInterface instance provided");
21.211 - return false;
21.212 - }
21.213 -
21.214 - if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
21.215 - {
21.216 - snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
21.217 - return false;
21.218 - }
21.219 -
21.220 - return true;
21.221 -}
21.222 -
21.223 -bool CExtension::Load(char *error, size_t maxlength)
21.224 -{
21.225 - CreateIdentity();
21.226 - if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
21.227 - {
21.228 - DestroyIdentity();
21.229 - return false;
21.230 - }
21.231 - else
21.232 - {
21.233 - /* Check if we're past load time */
21.234 - if (!g_SourceMod.IsMapLoading())
21.235 - {
21.236 - m_pAPI->OnExtensionsAllLoaded();
21.237 - }
21.238 - }
21.239 -
21.240 - return true;
21.241 -}
21.242 -
21.243 -void CExtension::CreateIdentity()
21.244 -{
21.245 - if (m_pIdentToken != NULL)
21.246 - {
21.247 - return;
21.248 - }
21.249 -
21.250 - m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
21.251 -}
21.252 -
21.253 -void CExtension::DestroyIdentity()
21.254 -{
21.255 - if (m_pIdentToken == NULL)
21.256 - {
21.257 - return;
21.258 - }
21.259 -
21.260 - g_ShareSys.DestroyIdentity(m_pIdentToken);
21.261 - m_pIdentToken = NULL;
21.262 -}
21.263 -
21.264 -void CExtension::MarkAllLoaded()
21.265 -{
21.266 - assert(m_bFullyLoaded == false);
21.267 - if (!m_bFullyLoaded)
21.268 - {
21.269 - m_bFullyLoaded = true;
21.270 - m_pAPI->OnExtensionsAllLoaded();
21.271 - }
21.272 -}
21.273 -
21.274 -void CExtension::AddPlugin(CPlugin *pPlugin)
21.275 -{
21.276 - /* Unfortunately we have to do this :( */
21.277 - if (m_Dependents.find(pPlugin) != m_Dependents.end())
21.278 - {
21.279 - m_Dependents.push_back(pPlugin);
21.280 - }
21.281 -}
21.282 -
21.283 -void CExtension::SetError(const char *error)
21.284 -{
21.285 - m_Error.assign(error);
21.286 -}
21.287 -
21.288 -IExtensionInterface *CExtension::GetAPI()
21.289 -{
21.290 - return m_pAPI;
21.291 -}
21.292 -
21.293 -const char *CExtension::GetFilename()
21.294 -{
21.295 - return m_File.c_str();
21.296 -}
21.297 -
21.298 -IdentityToken_t *CExtension::GetIdentity()
21.299 -{
21.300 - return m_pIdentToken;
21.301 -}
21.302 -
21.303 -bool CRemoteExtension::IsLoaded()
21.304 -{
21.305 - return (m_pAPI != NULL);
21.306 -}
21.307 -
21.308 -bool CLocalExtension::IsLoaded()
21.309 -{
21.310 - return (m_pLib != NULL);
21.311 -}
21.312 -
21.313 -void CExtension::AddDependency(const IfaceInfo *pInfo)
21.314 -{
21.315 - if (m_Deps.find(*pInfo) == m_Deps.end())
21.316 - {
21.317 - m_Deps.push_back(*pInfo);
21.318 - }
21.319 -}
21.320 -
21.321 -bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
21.322 -{
21.323 - return (i1.iface == i2.iface) && (i1.owner == i2.owner);
21.324 -}
21.325 -
21.326 -void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
21.327 -{
21.328 - IfaceInfo info;
21.329 - info.iface = iface;
21.330 - info.owner = pOther;
21.331 -
21.332 - List<IfaceInfo>::iterator iter;
21.333 - for (iter = m_ChildDeps.begin();
21.334 - iter != m_ChildDeps.end();
21.335 - iter++)
21.336 - {
21.337 - IfaceInfo &other = (*iter);
21.338 - if (other == info)
21.339 - {
21.340 - return;
21.341 - }
21.342 - }
21.343 -
21.344 - m_ChildDeps.push_back(info);
21.345 -}
21.346 -
21.347 -ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
21.348 -{
21.349 - List<IfaceInfo>::iterator iter = m_Deps.begin();
21.350 -
21.351 - if (iter == m_Deps.end())
21.352 - {
21.353 - return NULL;
21.354 - }
21.355 -
21.356 - if (pOwner)
21.357 - {
21.358 - *pOwner = (*iter).owner;
21.359 - }
21.360 - if (pInterface)
21.361 - {
21.362 - *pInterface = (*iter).iface;
21.363 - }
21.364 -
21.365 - List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
21.366 -
21.367 - return (ITERATOR *)pIter;
21.368 -}
21.369 -
21.370 -bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
21.371 -{
21.372 - List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
21.373 - List<IfaceInfo>::iterator _iter;
21.374 -
21.375 - if (_iter == m_Deps.end())
21.376 - {
21.377 - return false;
21.378 - }
21.379 -
21.380 - _iter++;
21.381 -
21.382 - if (pOwner)
21.383 - {
21.384 - *pOwner = (*_iter).owner;
21.385 - }
21.386 - if (pInterface)
21.387 - {
21.388 - *pInterface = (*_iter).iface;
21.389 - }
21.390 -
21.391 - *pIter = _iter;
21.392 -
21.393 - if (_iter == m_Deps.end())
21.394 - {
21.395 - return false;
21.396 - }
21.397 -
21.398 - return true;
21.399 -}
21.400 -
21.401 -void CExtension::FreeDependencyIterator(ITERATOR *iter)
21.402 -{
21.403 - List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
21.404 -
21.405 - delete pIter;
21.406 -}
21.407 -
21.408 -void CExtension::AddInterface(SMInterface *pInterface)
21.409 -{
21.410 - m_Interfaces.push_back(pInterface);
21.411 -}
21.412 -
21.413 -bool CExtension::IsRunning(char *error, size_t maxlength)
21.414 -{
21.415 - if (!IsLoaded())
21.416 - {
21.417 - if (error)
21.418 - {
21.419 - snprintf(error, maxlength, "%s", m_Error.c_str());
21.420 - }
21.421 - return false;
21.422 - }
21.423 -
21.424 - return m_pAPI->QueryRunning(error, maxlength);
21.425 -}
21.426 -
21.427 -void CExtension::AddLibrary(const char *library)
21.428 -{
21.429 - m_Libraries.push_back(library);
21.430 -}
21.431 -
21.432 -/*********************
21.433 - * EXTENSION MANAGER *
21.434 - *********************/
21.435 -
21.436 -void CExtensionManager::OnSourceModAllInitialized()
21.437 -{
21.438 - g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
21.439 - g_PluginSys.AddPluginsListener(this);
21.440 - g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
21.441 - g_ShareSys.AddInterface(NULL, this);
21.442 -}
21.443 -
21.444 -void CExtensionManager::OnSourceModShutdown()
21.445 -{
21.446 - g_RootMenu.RemoveRootConsoleCommand("exts", this);
21.447 - g_ShareSys.DestroyIdentType(g_ExtType);
21.448 -}
21.449 -
21.450 -void CExtensionManager::Shutdown()
21.451 -{
21.452 - List<CExtension *>::iterator iter;
21.453 -
21.454 - while ((iter = m_Libs.begin()) != m_Libs.end())
21.455 - {
21.456 - UnloadExtension((*iter));
21.457 - }
21.458 -}
21.459 -
21.460 -void CExtensionManager::TryAutoload()
21.461 -{
21.462 - char path[PLATFORM_MAX_PATH];
21.463 -
21.464 - g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
21.465 -
21.466 - IDirectory *pDir = g_LibSys.OpenDirectory(path);
21.467 - if (!pDir)
21.468 - {
21.469 - return;
21.470 - }
21.471 -
21.472 - const char *lfile;
21.473 - size_t len;
21.474 - while (pDir->MoreFiles())
21.475 - {
21.476 - if (pDir->IsEntryDirectory())
21.477 - {
21.478 - pDir->NextEntry();
21.479 - continue;
21.480 - }
21.481 -
21.482 - lfile = pDir->GetEntryName();
21.483 - len = strlen(lfile);
21.484 - if (len <= 9) /* size of ".autoload" */
21.485 - {
21.486 - pDir->NextEntry();
21.487 - continue;
21.488 - }
21.489 -
21.490 - if (strcmp(&lfile[len - 9], ".autoload") != 0)
21.491 - {
21.492 - pDir->NextEntry();
21.493 - continue;
21.494 - }
21.495 -
21.496 - char file[PLATFORM_MAX_PATH];
21.497 - len = UTIL_Format(file, sizeof(file), "%s", lfile);
21.498 - strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
21.499 -
21.500 - LoadAutoExtension(file);
21.501 -
21.502 - pDir->NextEntry();
21.503 - }
21.504 -}
21.505 -
21.506 -IExtension *CExtensionManager::LoadAutoExtension(const char *path)
21.507 -{
21.508 - if (!strstr(path, "." PLATFORM_LIB_EXT))
21.509 - {
21.510 - char newpath[PLATFORM_MAX_PATH];
21.511 - g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
21.512 - return LoadAutoExtension(newpath);
21.513 - }
21.514 -
21.515 - IExtension *pAlready;
21.516 - if ((pAlready=FindExtensionByFile(path)) != NULL)
21.517 - {
21.518 - return pAlready;
21.519 - }
21.520 -
21.521 - char error[256];
21.522 - CExtension *p = new CLocalExtension(path);
21.523 -
21.524 - /* We put us in the list beforehand so extensions that check for each other
21.525 - * won't recursively load each other.
21.526 - */
21.527 - m_Libs.push_back(p);
21.528 -
21.529 - if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
21.530 - {
21.531 - g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
21.532 - p->SetError(error);
21.533 - }
21.534 -
21.535 - return p;
21.536 -}
21.537 -
21.538 -IExtension *CExtensionManager::FindExtensionByFile(const char *file)
21.539 -{
21.540 - List<CExtension *>::iterator iter;
21.541 - CExtension *pExt;
21.542 -
21.543 - /* Chomp off the path */
21.544 - char lookup[PLATFORM_MAX_PATH];
21.545 - g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
21.546 -
21.547 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.548 - {
21.549 - pExt = (*iter);
21.550 - char short_file[PLATFORM_MAX_PATH];
21.551 - g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
21.552 - if (strcmp(lookup, short_file) == 0)
21.553 - {
21.554 - return pExt;
21.555 - }
21.556 - }
21.557 -
21.558 - /* If we got no results, test if there was a platform extension.
21.559 - * If not, add one.
21.560 - */
21.561 - if (!strstr(file, "." PLATFORM_LIB_EXT))
21.562 - {
21.563 - char path[PLATFORM_MAX_PATH];
21.564 - UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
21.565 - return FindExtensionByFile(path);
21.566 - }
21.567 -
21.568 - return NULL;
21.569 -}
21.570 -
21.571 -IExtension *CExtensionManager::FindExtensionByName(const char *ext)
21.572 -{
21.573 - List<CExtension *>::iterator iter;
21.574 - CExtension *pExt;
21.575 - IExtensionInterface *pAPI;
21.576 - const char *name;
21.577 -
21.578 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.579 - {
21.580 - pExt = (*iter);
21.581 - if (!pExt->IsLoaded())
21.582 - {
21.583 - continue;
21.584 - }
21.585 - if ((pAPI = pExt->GetAPI()) == NULL)
21.586 - {
21.587 - continue;
21.588 - }
21.589 - name = pAPI->GetExtensionName();
21.590 - if (!name)
21.591 - {
21.592 - continue;
21.593 - }
21.594 - if (strcmp(name, ext) == 0)
21.595 - {
21.596 - return pExt;
21.597 - }
21.598 - }
21.599 -
21.600 - return NULL;
21.601 -}
21.602 -
21.603 -IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
21.604 -{
21.605 - IExtension *pAlready;
21.606 - if ((pAlready=FindExtensionByFile(file)) != NULL)
21.607 - {
21.608 - return pAlready;
21.609 - }
21.610 -
21.611 - CExtension *pExt = new CLocalExtension(file);
21.612 -
21.613 - if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
21.614 - {
21.615 - pExt->Unload();
21.616 - delete pExt;
21.617 - return NULL;
21.618 - }
21.619 -
21.620 - /* :TODO: do QueryRunning check if the map is loaded */
21.621 -
21.622 - m_Libs.push_back(pExt);
21.623 -
21.624 - return pExt;
21.625 -}
21.626 -
21.627 -void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
21.628 -{
21.629 - CExtension *pExt = (CExtension *)pRequester;
21.630 - CExtension *pOwner = (CExtension *)pInfo->owner;
21.631 -
21.632 - pExt->AddDependency(pInfo);
21.633 -
21.634 - IExtensionInterface *pAPI = pExt->GetAPI();
21.635 - if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
21.636 - {
21.637 - pOwner->AddChildDependent(pExt, pInfo->iface);
21.638 - }
21.639 -}
21.640 -
21.641 -void CExtensionManager::AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface)
21.642 -{
21.643 - CExtension *pExt = (CExtension *)ext;
21.644 - CExtension *pOwner = GetExtensionFromIdent(other);
21.645 -
21.646 - IfaceInfo info;
21.647 -
21.648 - info.iface = (SMInterface *)iface;
21.649 - info.owner = pOwner;
21.650 -
21.651 - pExt->AddDependency(&info);
21.652 - pOwner->AddChildDependent(pExt, (SMInterface *)iface);
21.653 -}
21.654 -
21.655 -void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
21.656 -{
21.657 - CExtension *pExt = (CExtension *)pOwner;
21.658 -
21.659 - pExt->AddInterface(pInterface);
21.660 -}
21.661 -
21.662 -void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
21.663 -{
21.664 - CExtension *pExt = (CExtension *)pParent;
21.665 -
21.666 - pExt->AddPlugin(pPlugin);
21.667 -}
21.668 -
21.669 -void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
21.670 -{
21.671 - List<CExtension *>::iterator iter;
21.672 -
21.673 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.674 - {
21.675 - (*iter)->DropRefsTo((CPlugin *)plugin);
21.676 - }
21.677 -}
21.678 -
21.679 -CExtension *CExtensionManager::FindByOrder(unsigned int num)
21.680 -{
21.681 - if (num < 1 || num > m_Libs.size())
21.682 - {
21.683 - return NULL;
21.684 - }
21.685 -
21.686 - List<CExtension *>::iterator iter = m_Libs.begin();
21.687 -
21.688 - while (iter != m_Libs.end())
21.689 - {
21.690 - if (--num == 0)
21.691 - {
21.692 - return (*iter);
21.693 - }
21.694 - iter++;
21.695 - }
21.696 -
21.697 - return NULL;
21.698 -}
21.699 -
21.700 -bool CExtensionManager::UnloadExtension(IExtension *_pExt)
21.701 -{
21.702 - if (!_pExt)
21.703 - {
21.704 - return false;
21.705 - }
21.706 -
21.707 - CExtension *pExt = (CExtension *)_pExt;
21.708 -
21.709 - if (m_Libs.find(pExt) == m_Libs.end())
21.710 - {
21.711 - return false;
21.712 - }
21.713 -
21.714 - /* First remove us from internal lists */
21.715 - g_ShareSys.RemoveInterfaces(_pExt);
21.716 - m_Libs.remove(pExt);
21.717 -
21.718 - List<CExtension *> UnloadQueue;
21.719 -
21.720 - /* Handle dependencies */
21.721 - if (pExt->IsLoaded())
21.722 - {
21.723 - /* Unload any dependent plugins */
21.724 - List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
21.725 - while (p_iter != pExt->m_Dependents.end())
21.726 - {
21.727 - /* We have to manually unlink ourselves here, since we're no longer being managed */
21.728 - g_PluginSys.UnloadPlugin((*p_iter));
21.729 - p_iter = pExt->m_Dependents.erase(p_iter);
21.730 - }
21.731 -
21.732 - List<String>::iterator s_iter;
21.733 - for (s_iter = pExt->m_Libraries.begin();
21.734 - s_iter != pExt->m_Libraries.end();
21.735 - s_iter++)
21.736 - {
21.737 - g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
21.738 - }
21.739 -
21.740 - /* Notify and/or unload all dependencies */
21.741 - List<CExtension *>::iterator c_iter;
21.742 - CExtension *pDep;
21.743 - IExtensionInterface *pAPI;
21.744 - for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
21.745 - {
21.746 - pDep = (*c_iter);
21.747 - if ((pAPI=pDep->GetAPI()) == NULL)
21.748 - {
21.749 - continue;
21.750 - }
21.751 - if (pDep == pExt)
21.752 - {
21.753 - continue;
21.754 - }
21.755 - /* Now, get its dependency list */
21.756 - bool dropped = false;
21.757 - List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
21.758 - while (i_iter != pDep->m_Deps.end())
21.759 - {
21.760 - if ((*i_iter).owner == _pExt)
21.761 - {
21.762 - if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
21.763 - {
21.764 - if (!dropped)
21.765 - {
21.766 - dropped = true;
21.767 - UnloadQueue.push_back(pDep);
21.768 - }
21.769 - }
21.770 - pAPI->NotifyInterfaceDrop((*i_iter).iface);
21.771 - i_iter = pDep->m_Deps.erase(i_iter);
21.772 - }
21.773 - else
21.774 - {
21.775 - i_iter++;
21.776 - }
21.777 - }
21.778 - /* Flush out any back references to this plugin */
21.779 - i_iter = pDep->m_ChildDeps.begin();
21.780 - while (i_iter != pDep->m_ChildDeps.end())
21.781 - {
21.782 - if ((*i_iter).owner == pExt)
21.783 - {
21.784 - i_iter = pDep->m_ChildDeps.erase(i_iter);
21.785 - }
21.786 - else
21.787 - {
21.788 - i_iter++;
21.789 - }
21.790 - }
21.791 - }
21.792 -
21.793 - /* Unbind our natives from Core */
21.794 - pExt->DropEverything();
21.795 - }
21.796 -
21.797 - IdentityToken_t *pIdentity;
21.798 - if ((pIdentity = pExt->GetIdentity()) != NULL)
21.799 - {
21.800 - SMGlobalClass *glob = SMGlobalClass::head;
21.801 - while (glob)
21.802 - {
21.803 - glob->OnSourceModIdentityDropped(pIdentity);
21.804 - glob = glob->m_pGlobalClassNext;
21.805 - }
21.806 - }
21.807 -
21.808 - /* Tell it to unload */
21.809 - if (pExt->IsLoaded())
21.810 - {
21.811 - IExtensionInterface *pAPI = pExt->GetAPI();
21.812 - pAPI->OnExtensionUnload();
21.813 - }
21.814 -
21.815 - pExt->Unload();
21.816 - delete pExt;
21.817 -
21.818 - List<CExtension *>::iterator iter;
21.819 - for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
21.820 - {
21.821 - /* NOTE: This is safe because the unload function backs out of anything not present */
21.822 - UnloadExtension((*iter));
21.823 - }
21.824 -
21.825 - return true;
21.826 -}
21.827 -
21.828 -void CExtensionManager::MarkAllLoaded()
21.829 -{
21.830 - List<CExtension *>::iterator iter;
21.831 - CExtension *pExt;
21.832 -
21.833 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.834 - {
21.835 - pExt = (*iter);
21.836 - if (!pExt->IsLoaded())
21.837 - {
21.838 - continue;
21.839 - }
21.840 - if (pExt->m_bFullyLoaded)
21.841 - {
21.842 - continue;
21.843 - }
21.844 - pExt->MarkAllLoaded();
21.845 - }
21.846 -}
21.847 -
21.848 -void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
21.849 -{
21.850 - /* This function doesn't really need to do anything now. We make sure the
21.851 - * other extension is loaded, but handling of dependencies is really done
21.852 - * by the interface fetcher.
21.853 - */
21.854 - if (required || autoload)
21.855 - {
21.856 - LoadAutoExtension(file);
21.857 - }
21.858 -}
21.859 -
21.860 -void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
21.861 -{
21.862 - int argcount = command.ArgC();
21.863 - if (argcount >= 3)
21.864 - {
21.865 - const char *cmd = command.Arg(2);
21.866 - if (strcmp(cmd, "list") == 0)
21.867 - {
21.868 - List<CExtension *>::iterator iter;
21.869 - CExtension *pExt;
21.870 - unsigned int num = 1;
21.871 - switch (m_Libs.size())
21.872 - {
21.873 - case 1:
21.874 - {
21.875 - g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
21.876 - break;
21.877 - }
21.878 - case 0:
21.879 - {
21.880 - g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
21.881 - break;
21.882 - }
21.883 - default:
21.884 - {
21.885 - g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
21.886 - break;
21.887 - }
21.888 - }
21.889 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
21.890 - {
21.891 - pExt = (*iter);
21.892 - if (pExt->IsLoaded())
21.893 - {
21.894 - char error[255];
21.895 - if (!pExt->IsRunning(error, sizeof(error)))
21.896 - {
21.897 - g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
21.898 - }
21.899 - else
21.900 - {
21.901 - IExtensionInterface *pAPI = pExt->GetAPI();
21.902 - const char *name = pAPI->GetExtensionName();
21.903 - const char *version = pAPI->GetExtensionVerString();
21.904 - const char *descr = pAPI->GetExtensionDescription();
21.905 - g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
21.906 - }
21.907 - } else {
21.908 - g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
21.909 - }
21.910 - }
21.911 - return;
21.912 - }
21.913 - else if (strcmp(cmd, "info") == 0)
21.914 - {
21.915 - if (argcount < 4)
21.916 - {
21.917 - g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
21.918 - return;
21.919 - }
21.920 -
21.921 - const char *sId = command.Arg(3);
21.922 - unsigned int id = atoi(sId);
21.923 - if (id <= 0)
21.924 - {
21.925 - g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
21.926 - return;
21.927 - }
21.928 -
21.929 - if (m_Libs.size() == 0)
21.930 - {
21.931 - g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
21.932 - return;
21.933 - }
21.934 -
21.935 - if (id > m_Libs.size())
21.936 - {
21.937 - g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
21.938 - return;
21.939 - }
21.940 -
21.941 - List<CExtension *>::iterator iter = m_Libs.begin();
21.942 - CExtension *pExt = NULL;
21.943 - while (iter != m_Libs.end())
21.944 - {
21.945 - if (--id == 0)
21.946 - {
21.947 - pExt = (*iter);
21.948 - break;
21.949 - }
21.950 - iter++;
21.951 - }
21.952 - /* This should never happen */
21.953 - if (!pExt)
21.954 - {
21.955 - g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
21.956 - return;
21.957 - }
21.958 -
21.959 - if (!pExt->IsLoaded())
21.960 - {
21.961 - g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
21.962 - g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
21.963 - }
21.964 - else
21.965 - {
21.966 - char error[255];
21.967 - if (!pExt->IsRunning(error, sizeof(error)))
21.968 - {
21.969 - g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
21.970 - g_RootMenu.ConsolePrint(" Loaded: Yes");
21.971 - g_RootMenu.ConsolePrint(" Running: No (%s)", error);
21.972 - }
21.973 - else
21.974 - {
21.975 - IExtensionInterface *pAPI = pExt->GetAPI();
21.976 - g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
21.977 - g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
21.978 - g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
21.979 - g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
21.980 - g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
21.981 -
21.982 - if (pExt->IsExternal())
21.983 - {
21.984 - g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
21.985 - }
21.986 - else if (pAPI->IsMetamodExtension())
21.987 - {
21.988 - g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
21.989 - }
21.990 - else
21.991 - {
21.992 - g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
21.993 - }
21.994 - }
21.995 - }
21.996 - return;
21.997 - }
21.998 - else if (strcmp(cmd, "unload") == 0)
21.999 - {
21.1000 - if (argcount < 4)
21.1001 - {
21.1002 - g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
21.1003 - return;
21.1004 - }
21.1005 -
21.1006 - const char *arg = command.Arg(3);
21.1007 - unsigned int num = atoi(arg);
21.1008 - CExtension *pExt = FindByOrder(num);
21.1009 -
21.1010 - if (!pExt)
21.1011 - {
21.1012 - g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
21.1013 - return;
21.1014 - }
21.1015 -
21.1016 - if (argcount > 4 && pExt->unload_code)
21.1017 - {
21.1018 - const char *unload = command.Arg(4);
21.1019 - if (pExt->unload_code == (unsigned)atoi(unload))
21.1020 - {
21.1021 - char filename[PLATFORM_MAX_PATH];
21.1022 - snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
21.1023 - UnloadExtension(pExt);
21.1024 - g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
21.1025 - }
21.1026 - else
21.1027 - {
21.1028 - g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
21.1029 - }
21.1030 - return;
21.1031 - }
21.1032 -
21.1033 - if (!pExt->IsLoaded()
21.1034 - || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
21.1035 - {
21.1036 - char filename[PLATFORM_MAX_PATH];
21.1037 - snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
21.1038 - UnloadExtension(pExt);
21.1039 - g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
21.1040 - return;
21.1041 - }
21.1042 - else
21.1043 - {
21.1044 - List<CPlugin *> plugins;
21.1045 - if (pExt->m_ChildDeps.size())
21.1046 - {
21.1047 - g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
21.1048 - List<CExtension *>::iterator iter;
21.1049 - CExtension *pOther;
21.1050 - /* Get list of all extensions */
21.1051 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.1052 - {
21.1053 - List<IfaceInfo>::iterator i_iter;
21.1054 - pOther = (*iter);
21.1055 - if (!pOther->IsLoaded() || pOther == pExt)
21.1056 - {
21.1057 - continue;
21.1058 - }
21.1059 - /* Get their dependencies */
21.1060 - for (i_iter=pOther->m_Deps.begin();
21.1061 - i_iter!=pOther->m_Deps.end();
21.1062 - i_iter++)
21.1063 - {
21.1064 - /* Is this dependency to us? */
21.1065 - if ((*i_iter).owner != pExt)
21.1066 - {
21.1067 - continue;
21.1068 - }
21.1069 - /* Will our dependent care? */
21.1070 - if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
21.1071 - {
21.1072 - g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
21.1073 - /* Add to plugin unload list */
21.1074 - List<CPlugin *>::iterator p_iter;
21.1075 - for (p_iter=pOther->m_Dependents.begin();
21.1076 - p_iter!=pOther->m_Dependents.end();
21.1077 - p_iter++)
21.1078 - {
21.1079 - if (plugins.find((*p_iter)) == plugins.end())
21.1080 - {
21.1081 - plugins.push_back((*p_iter));
21.1082 - }
21.1083 - }
21.1084 - }
21.1085 - }
21.1086 - }
21.1087 - }
21.1088 - if (pExt->m_Dependents.size())
21.1089 - {
21.1090 - g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
21.1091 - List<CPlugin *>::iterator iter;
21.1092 - CPlugin *pPlugin;
21.1093 - for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
21.1094 - {
21.1095 - pPlugin = (*iter);
21.1096 - if (plugins.find(pPlugin) == plugins.end())
21.1097 - {
21.1098 - plugins.push_back(pPlugin);
21.1099 - }
21.1100 - }
21.1101 - for (iter = plugins.begin(); iter != plugins.end(); iter++)
21.1102 - {
21.1103 - pPlugin = (*iter);
21.1104 - g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
21.1105 - }
21.1106 - }
21.1107 - srand(static_cast<int>(time(NULL)));
21.1108 - pExt->unload_code = (rand() % 877) + 123; //123 to 999
21.1109 - g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
21.1110 - g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
21.1111 -
21.1112 - return;
21.1113 - }
21.1114 - }
21.1115 - }
21.1116 -
21.1117 - g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
21.1118 - g_RootMenu.DrawGenericOption("info", "Extra extension information");
21.1119 - g_RootMenu.DrawGenericOption("list", "List extensions");
21.1120 - g_RootMenu.DrawGenericOption("unload", "Unload an extension");
21.1121 -}
21.1122 -
21.1123 -CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
21.1124 -{
21.1125 - if (ptr->type == g_ExtType)
21.1126 - {
21.1127 - return (CExtension *)(ptr->ptr);
21.1128 - }
21.1129 -
21.1130 - return NULL;
21.1131 -}
21.1132 -
21.1133 -CExtensionManager::CExtensionManager()
21.1134 -{
21.1135 -}
21.1136 -
21.1137 -CExtensionManager::~CExtensionManager()
21.1138 -{
21.1139 -}
21.1140 -
21.1141 -void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
21.1142 -{
21.1143 - CExtension *pExt = (CExtension *)pSource;
21.1144 - pExt->AddLibrary(library);
21.1145 - g_PluginSys.OnLibraryAction(library, false, false);
21.1146 -}
21.1147 -
21.1148 -bool CExtensionManager::LibraryExists(const char *library)
21.1149 -{
21.1150 - CExtension *pExt;
21.1151 -
21.1152 - for (List<CExtension *>::iterator iter = m_Libs.begin();
21.1153 - iter != m_Libs.end();
21.1154 - iter++)
21.1155 - {
21.1156 - pExt = (*iter);
21.1157 - for (List<String>::iterator s_iter = pExt->m_Libraries.begin();
21.1158 - s_iter != pExt->m_Libraries.end();
21.1159 - s_iter++)
21.1160 - {
21.1161 - if ((*s_iter).compare(library) == 0)
21.1162 - {
21.1163 - return true;
21.1164 - }
21.1165 - }
21.1166 - }
21.1167 -
21.1168 - return false;
21.1169 -}
21.1170 -
21.1171 -IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
21.1172 - const char *filepath,
21.1173 - const char *filename,
21.1174 - char *error,
21.1175 - size_t maxlength)
21.1176 -{
21.1177 - IExtension *pAlready;
21.1178 - if ((pAlready=FindExtensionByFile(filename)) != NULL)
21.1179 - {
21.1180 - return pAlready;
21.1181 - }
21.1182 -
21.1183 - CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
21.1184 -
21.1185 - if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
21.1186 - {
21.1187 - pExt->Unload();
21.1188 - delete pExt;
21.1189 - return NULL;
21.1190 - }
21.1191 -
21.1192 - m_Libs.push_back(pExt);
21.1193 -
21.1194 - return pExt;
21.1195 -}
21.1196 -
21.1197 -void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
21.1198 -{
21.1199 - IExtensionInterface *pAPI;
21.1200 - List<CExtension *>::iterator iter;
21.1201 -
21.1202 - for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
21.1203 - {
21.1204 - if ((pAPI = (*iter)->GetAPI()) == NULL)
21.1205 - {
21.1206 - continue;
21.1207 - }
21.1208 - if (pAPI->GetExtensionVersion() > 3)
21.1209 - {
21.1210 - pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);
21.1211 - }
21.1212 - }
21.1213 -}
22.1 --- a/core/systems/ExtensionSys.h Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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(¶m->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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 2008 -0600
32.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
32.3 @@ -1,460 +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 SOURCE_ENGINE == SE_LEFT4DEAD
32.54 -#include "convar_sm_l4d.h"
32.55 -#elif SOURCE_ENGINE == SE_ORANGEBOX
32.56 -#include "convar_sm_ob.h"
32.57 -#else
32.58 -#include "convar_sm.h"
32.59 -#endif
32.60 -#include "ITranslator.h"
32.61 -#include "NativeOwner.h"
32.62 -#include "ShareSys.h"
32.63 -
32.64 -using namespace SourceHook;
32.65 -
32.66 -/**
32.67 - * NOTES:
32.68 - *
32.69 - * UPDATE 2008-03-11: These comments are horribly out of date. They paint a good overall
32.70 - * picture of how PluginSys works, but things like dependencies and fake natives have
32.71 - * complicated things quite a bit.
32.72 - *
32.73 - * Currently this system needs a lot of work but it's good skeletally. Plugin creation
32.74 - * is done without actually compiling anything. This is done by Load functions in the
32.75 - * manager. This will need a rewrite when we add context switching.
32.76 - *
32.77 - * The plugin object itself has a few things to note. The most important is that it stores
32.78 - * a table of function objects. The manager marshals allocation and freeing of these objects.
32.79 - * The plugin object can be in erroneous states, they are:
32.80 - * Plugin_Error --> Some error occurred any time during or after compilation.
32.81 - * This error can be cleared since the plugin itself is valid.
32.82 - * However, the state itself being set prevents any runtime action.
32.83 - * Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
32.84 - *
32.85 - * If a plugin fails to load externally, it is never added to the internal tracker. However,
32.86 - * plugins that failed to load from the internal loading mechanism are always tracked. This
32.87 - * allows users to see which automatically loaded plugins failed, and makes the interface a bit
32.88 - * more flexible.
32.89 - *
32.90 - * Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
32.91 - * for execution. SourceMod is a two pass system, and even though the second pass is not implemented
32.92 - * yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
32.93 - * implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
32.94 - *
32.95 - * The two pass loading mechanism is described below. Modules/natives are not implemented yet.
32.96 - * PASS ONE: All loadable plugins are found and have the following steps performed:
32.97 - * 1. Loading and compilation is attempted.
32.98 - * 2. If successful, all natives from Core are added.
32.99 - * 3. OnPluginLoad() is called.
32.100 - * 4. If failed, any user natives are scrapped and the process halts here.
32.101 - * 5. If successful, the plugin is ready for Pass 2.
32.102 - * INTERMEDIATE:
32.103 - * 1. All forced modules are loaded.
32.104 - * PASS TWO: All loaded plugins are found and have these steps performed:
32.105 - * 1. Any modules referenced in the plugin that are not already loaded, are loaded.
32.106 - * 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
32.107 - * 3. If any natives are unresolved, check if they are found in the user-natives pool.
32.108 - * 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
32.109 - * 5. If the filter fails, the plugin is marked as failed.
32.110 - * 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
32.111 - * Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
32.112 - * PASS THREE (not a real pass):
32.113 - * 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
32.114 - */
32.115 -
32.116 -enum LoadRes
32.117 -{
32.118 - LoadRes_Successful,
32.119 - LoadRes_AlreadyLoaded,
32.120 - LoadRes_Failure,
32.121 - LoadRes_NeverLoad
32.122 -};
32.123 -
32.124 -struct AutoConfig
32.125 -{
32.126 - String autocfg;
32.127 - String folder;
32.128 - bool create;
32.129 -};
32.130 -
32.131 -class CPlugin;
32.132 -
32.133 -class CPlugin :
32.134 - public IPlugin,
32.135 - public CNativeOwner
32.136 -{
32.137 - friend class CPluginManager;
32.138 - friend class CFunction;
32.139 -public:
32.140 - CPlugin(const char *file);
32.141 - ~CPlugin();
32.142 -public:
32.143 - PluginType GetType();
32.144 - SourcePawn::IPluginContext *GetBaseContext();
32.145 - sp_context_t *GetContext();
32.146 - void *GetPluginStructure();
32.147 - const char *GetFilename();
32.148 - bool IsDebugging();
32.149 - PluginStatus GetStatus();
32.150 - const sm_plugininfo_t *GetPublicInfo();
32.151 - bool SetPauseState(bool paused);
32.152 - unsigned int GetSerial();
32.153 - IdentityToken_t *GetIdentity();
32.154 - unsigned int CalcMemUsage();
32.155 - bool SetProperty(const char *prop, void *ptr);
32.156 - bool GetProperty(const char *prop, void **ptr, bool remove=false);
32.157 - void DropEverything();
32.158 - SourcePawn::IPluginRuntime *GetRuntime();
32.159 -public:
32.160 - /**
32.161 - * Creates a plugin object with default values.
32.162 - * If an error buffer is specified, and an error occurs, the error will be copied to the buffer
32.163 - * and NULL will be returned.
32.164 - * If an error buffer is not specified, the error will be copied to an internal buffer and
32.165 - * a valid (but error-stated) CPlugin will be returned.
32.166 - */
32.167 - static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
32.168 -public:
32.169 -
32.170 - /**
32.171 - * Sets an error state on the plugin
32.172 - */
32.173 - void SetErrorState(PluginStatus status, const char *error_fmt, ...);
32.174 -
32.175 - /**
32.176 - * Initializes the plugin's identity information
32.177 - */
32.178 - void InitIdentity();
32.179 -
32.180 - /**
32.181 - * Calls the OnPluginLoad function, and sets any failed states if necessary.
32.182 - * NOTE: Valid pre-states are: Plugin_Created
32.183 - * NOTE: If validated, plugin state is changed to Plugin_Loaded
32.184 - *
32.185 - * If the error buffer is NULL, the error message is cached locally.
32.186 - */
32.187 - bool Call_AskPluginLoad(char *error, size_t maxlength);
32.188 -
32.189 - /**
32.190 - * Calls the OnPluginStart function.
32.191 - * NOTE: Valid pre-states are: Plugin_Created
32.192 - * NOTE: Post-state will be Plugin_Running
32.193 - */
32.194 - void Call_OnPluginStart();
32.195 -
32.196 - /**
32.197 - * Calls the OnPluginEnd function.
32.198 - */
32.199 - void Call_OnPluginEnd();
32.200 -
32.201 - /**
32.202 - * Calls the OnAllPluginsLoaded function.
32.203 - */
32.204 - void Call_OnAllPluginsLoaded();
32.205 -
32.206 - /**
32.207 - * Returns true if a plugin is usable.
32.208 - */
32.209 - bool IsRunnable();
32.210 -
32.211 - /**
32.212 - * Get languages info.
32.213 - */
32.214 - IPhraseCollection *GetPhrases();
32.215 -public:
32.216 - /**
32.217 - * Returns the modification time during last plugin load.
32.218 - */
32.219 - time_t GetTimeStamp();
32.220 -
32.221 - /**
32.222 - * Returns the current modification time of the plugin file.
32.223 - */
32.224 - time_t GetFileTimeStamp();
32.225 -
32.226 - /**
32.227 - * Returns true if the plugin was running, but is now invalid.
32.228 - */
32.229 - bool WasRunning();
32.230 -
32.231 - Handle_t GetMyHandle();
32.232 -
32.233 - bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
32.234 - void AddConfig(bool autoCreate, const char *cfg, const char *folder);
32.235 - unsigned int GetConfigCount();
32.236 - AutoConfig *GetConfig(unsigned int i);
32.237 - inline void AddLibrary(const char *name)
32.238 - {
32.239 - m_Libraries.push_back(name);
32.240 - }
32.241 - void LibraryActions(bool dropping);
32.242 - void SyncMaxClients(int max_clients);
32.243 -protected:
32.244 - bool UpdateInfo();
32.245 - void SetTimeStamp(time_t t);
32.246 - void DependencyDropped(CPlugin *pOwner);
32.247 -private:
32.248 - PluginType m_type;
32.249 - char m_filename[PLATFORM_MAX_PATH];
32.250 - PluginStatus m_status;
32.251 - unsigned int m_serial;
32.252 - sm_plugininfo_t m_info;
32.253 - char m_errormsg[256];
32.254 - time_t m_LastAccess;
32.255 - IdentityToken_t *m_ident;
32.256 - Handle_t m_handle;
32.257 - bool m_WasRunning;
32.258 - IPhraseCollection *m_pPhrases;
32.259 - List<String> m_RequiredLibs;
32.260 - List<String> m_Libraries;
32.261 - Trie *m_pProps;
32.262 - bool m_FakeNativesMissing;
32.263 - bool m_LibraryMissing;
32.264 - CVector<AutoConfig *> m_configs;
32.265 - bool m_bGotAllLoaded;
32.266 - int m_FileVersion;
32.267 - char m_DateTime[256];
32.268 - IPluginRuntime *m_pRuntime;
32.269 - IPluginContext *m_pContext;
32.270 - sp_pubvar_t *m_MaxClientsVar;
32.271 -};
32.272 -
32.273 -class CPluginManager :
32.274 - public IPluginManager,
32.275 - public SMGlobalClass,
32.276 - public IHandleTypeDispatch,
32.277 - public IRootConsoleCommand
32.278 -{
32.279 - friend class CPlugin;
32.280 -public:
32.281 - CPluginManager();
32.282 - ~CPluginManager();
32.283 -public:
32.284 - /* Implements iterator class */
32.285 - class CPluginIterator : public IPluginIterator
32.286 - {
32.287 - public:
32.288 - CPluginIterator(List<CPlugin *> *mylist);
32.289 - virtual ~CPluginIterator();
32.290 - virtual bool MorePlugins();
32.291 - virtual IPlugin *GetPlugin();
32.292 - virtual void NextPlugin();
32.293 - void Release();
32.294 - public:
32.295 - void Reset();
32.296 - private:
32.297 - List<CPlugin *> *mylist;
32.298 - List<CPlugin *>::iterator current;
32.299 - };
32.300 - friend class CPluginManager::CPluginIterator;
32.301 -public: //IPluginManager
32.302 - IPlugin *LoadPlugin(const char *path,
32.303 - bool debug,
32.304 - PluginType type,
32.305 - char error[],
32.306 - size_t maxlength,
32.307 - bool *wasloaded);
32.308 - bool UnloadPlugin(IPlugin *plugin);
32.309 - IPlugin *FindPluginByContext(const sp_context_t *ctx);
32.310 - unsigned int GetPluginCount();
32.311 - IPluginIterator *GetPluginIterator();
32.312 - void AddPluginsListener(IPluginsListener *listener);
32.313 - void RemovePluginsListener(IPluginsListener *listener);
32.314 -public: //SMGlobalClass
32.315 - void OnSourceModAllInitialized();
32.316 - void OnSourceModShutdown();
32.317 - void OnSourceModMaxPlayersChanged(int newvalue);
32.318 -public: //IHandleTypeDispatch
32.319 - void OnHandleDestroy(HandleType_t type, void *object);
32.320 - bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
32.321 -public: //IRootConsoleCommand
32.322 - void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
32.323 -public:
32.324 - /**
32.325 - * Loads all plugins not yet loaded
32.326 - */
32.327 - void LoadAll_FirstPass(const char *config, const char *basedir);
32.328 -
32.329 - /**
32.330 - * Runs the second loading pass for all plugins
32.331 - */
32.332 - void LoadAll_SecondPass();
32.333 -
32.334 - /**
32.335 - * Tests a plugin file mask against a local folder.
32.336 - * The alias is searched backwards from localdir - i.e., given this input:
32.337 - * csdm/ban csdm/ban
32.338 - * ban csdm/ban
32.339 - * csdm/ban optional/csdm/ban
32.340 - * All of these will return true for an alias match.
32.341 - * Wildcards are allowed in the filename.
32.342 - */
32.343 - bool TestAliasMatch(const char *alias, const char *localdir);
32.344 -
32.345 - /**
32.346 - * Returns whether anything loaded will be a late load.
32.347 - */
32.348 - bool IsLateLoadTime() const;
32.349 -
32.350 - /**
32.351 - * Converts a Handle to an IPlugin if possible.
32.352 - */
32.353 - IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
32.354 -
32.355 - /**
32.356 - * Finds a plugin based on its index. (starts on index 1)
32.357 - */
32.358 - CPlugin *GetPluginByOrder(int num);
32.359 -
32.360 - int GetOrderOfPlugin(IPlugin *pl);
32.361 -
32.362 - /**
32.363 - * Internal version of FindPluginByContext()
32.364 - */
32.365 - CPlugin *GetPluginByCtx(const sp_context_t *ctx);
32.366 -
32.367 - /**
32.368 - * Gets status text for a status code
32.369 - */
32.370 - const char *GetStatusText(PluginStatus status);
32.371 -
32.372 - /**
32.373 - * Reload or update plugins on level shutdown.
32.374 - */
32.375 - void ReloadOrUnloadPlugins();
32.376 -
32.377 - /**
32.378 - * Add public functions from all running or paused
32.379 - * plugins to the specified forward if the names match.
32.380 - */
32.381 - void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
32.382 -
32.383 - /**
32.384 - * Iterates through plugins to call OnAllPluginsLoaded.
32.385 - */
32.386 - void AllPluginsLoaded();
32.387 -
32.388 - CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
32.389 -
32.390 - void Shutdown();
32.391 -
32.392 - void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
32.393 -
32.394 - bool LibraryExists(const char *lib);
32.395 -
32.396 - bool ReloadPlugin(CPlugin *pl);
32.397 -
32.398 - void UnloadAll();
32.399 -
32.400 - CPlugin *FindPluginByConsoleArg(const char *arg);
32.401 -
32.402 - void SyncMaxClients(int max_clients);
32.403 -private:
32.404 - LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
32.405 -
32.406 - void LoadAutoPlugin(const char *plugin);
32.407 -
32.408 - /**
32.409 - * Recursively loads all plugins in the given directory.
32.410 - */
32.411 - void LoadPluginsFromDir(const char *basedir, const char *localdir);
32.412 -
32.413 - /**
32.414 - * Adds a plugin object. This is wrapped by LoadPlugin functions.
32.415 - */
32.416 - void AddPlugin(CPlugin *pPlugin);
32.417 -
32.418 - /**
32.419 - * Runs the second loading pass on a plugin.
32.420 - */
32.421 - bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
32.422 -
32.423 - /**
32.424 - * Runs an extension pass on a plugin.
32.425 - */
32.426 - bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
32.427 -
32.428 - /**
32.429 - * Manages required natives.
32.430 - */
32.431 - bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
32.432 -
32.433 - void _SetPauseState(CPlugin *pPlugin, bool pause);
32.434 -protected:
32.435 - /**
32.436 - * Caching internal objects
32.437 - */
32.438 - void ReleaseIterator(CPluginIterator *iter);
32.439 -public:
32.440 - inline IdentityToken_t *GetIdentity()
32.441 - {
32.442 - return m_MyIdent;
32.443 - }
32.444 -private:
32.445 - void TryRefreshDependencies(CPlugin *pOther);
32.446 -private:
32.447 - List<IPluginsListener *> m_listeners;
32.448 - List<CPlugin *> m_plugins;
32.449 - CStack<CPluginManager::CPluginIterator *> m_iters;
32.450 - CPluginInfoDatabase m_PluginInfo;
32.451 - Trie *m_LoadLookup;
32.452 - bool m_AllPluginsLoaded;
32.453 - IdentityToken_t *m_MyIdent;
32.454 -
32.455 - /* Dynamic native stuff */
32.456 - List<FakeNative *> m_Natives;
32.457 -
32.458 - bool m_LoadingLocked;
32.459 -};
32.460 -
32.461 -extern CPluginManager g_PluginSys;
32.462 -
32.463 -#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
33.1 --- a/core/systems/ShareSys.cpp Wed Nov 19 02:14:43 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 Wed Nov 19 02:14:43 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_
35.1 --- a/pushbuild.txt Wed Nov 19 02:14:43 2008 -0600
35.2 +++ b/pushbuild.txt Wed Nov 19 02:16:45 2008 -0600
35.3 @@ -1,1 +1,1 @@
35.4 -13
35.5 +a billion and TRILLIONS