jit refactoring branch
--HG-- branch : refac-jit extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/branches/refac-jit%402369
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
|
||||
|
||||
#include <IExtensionSys.h>
|
||||
#include <ILibrarySys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_string.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_globals.h"
|
||||
#include "ShareSys.h"
|
||||
#include <ISmmAPI.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <IRootConsoleMenu.h>
|
||||
#include "PluginSys.h"
|
||||
#include "NativeOwner.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
using namespace SourceHook;
|
||||
|
||||
class CExtension;
|
||||
|
||||
struct sm_extnative_t
|
||||
{
|
||||
CExtension *owner;
|
||||
const sp_nativeinfo_t *info;
|
||||
};
|
||||
|
||||
class CExtension :
|
||||
public IExtension,
|
||||
public CNativeOwner
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
public:
|
||||
virtual ~CExtension();
|
||||
public: //IExtension
|
||||
IExtensionInterface *GetAPI();
|
||||
const char *GetFilename();
|
||||
IdentityToken_t *GetIdentity();
|
||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||
void FreeDependencyIterator(ITERATOR *iter);
|
||||
bool IsRunning(char *error, size_t maxlength);
|
||||
public:
|
||||
void SetError(const char *error);
|
||||
void AddDependency(const IfaceInfo *pInfo);
|
||||
void AddChildDependent(CExtension *pOther, SMInterface *iface);
|
||||
void AddInterface(SMInterface *pInterface);
|
||||
void AddPlugin(CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddLibrary(const char *library);
|
||||
public:
|
||||
virtual bool Load(char *error, size_t maxlength);
|
||||
virtual bool IsLoaded() =0;
|
||||
virtual void Unload() =0;
|
||||
protected:
|
||||
void Initialize(const char *filename, const char *path);
|
||||
bool PerformAPICheck(char *error, size_t maxlength);
|
||||
void CreateIdentity();
|
||||
void DestroyIdentity();
|
||||
protected:
|
||||
IdentityToken_t *m_pIdentToken;
|
||||
IExtensionInterface *m_pAPI;
|
||||
String m_File;
|
||||
String m_Path;
|
||||
String m_Error;
|
||||
List<IfaceInfo> m_Deps; /** Dependencies */
|
||||
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
||||
List<SMInterface *> m_Interfaces;
|
||||
List<String> m_Libraries;
|
||||
unsigned int unload_code;
|
||||
bool m_bFullyLoaded;
|
||||
};
|
||||
|
||||
class CLocalExtension : public CExtension
|
||||
{
|
||||
public:
|
||||
CLocalExtension(const char *filename);
|
||||
public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool IsExternal();
|
||||
private:
|
||||
PluginId m_PlId;
|
||||
ILibrary *m_pLib;
|
||||
};
|
||||
|
||||
class CRemoteExtension : public CExtension
|
||||
{
|
||||
public:
|
||||
CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path);
|
||||
public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool IsExternal();
|
||||
};
|
||||
|
||||
class CExtensionManager :
|
||||
public IExtensionManager,
|
||||
public SMGlobalClass,
|
||||
public IPluginsListener,
|
||||
public IRootConsoleCommand
|
||||
{
|
||||
public:
|
||||
CExtensionManager();
|
||||
~CExtensionManager();
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
public: //IExtensionManager
|
||||
IExtension *LoadExtension(const char *path,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
bool UnloadExtension(IExtension *pExt);
|
||||
IExtension *FindExtensionByFile(const char *file);
|
||||
IExtension *FindExtensionByName(const char *ext);
|
||||
IExtension *LoadExternal(IExtensionInterface *pInterface,
|
||||
const char *filepath,
|
||||
const char *filename,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
public: //IPluginsListener
|
||||
void OnPluginDestroyed(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
IExtension *LoadAutoExtension(const char *path);
|
||||
void BindDependency(IExtension *pOwner, IfaceInfo *pInfo);
|
||||
void AddInterface(IExtension *pOwner, SMInterface *pInterface);
|
||||
void BindChildPlugin(IExtension *pParent, CPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddDependency(IExtension *pSource, const char *file, bool required, bool autoload);
|
||||
void TryAutoload();
|
||||
void AddLibrary(IExtension *pSource, const char *library);
|
||||
bool LibraryExists(const char *library);
|
||||
void CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax);
|
||||
void AddRawDependency(IExtension *ext, IdentityToken_t *other, void *iface);
|
||||
public:
|
||||
CExtension *GetExtensionFromIdent(IdentityToken_t *ptr);
|
||||
void Shutdown();
|
||||
CNativeOwner *GetNativeOwner(IExtension *pExt)
|
||||
{
|
||||
CExtension *p = (CExtension *)pExt;
|
||||
return p;
|
||||
}
|
||||
private:
|
||||
CExtension *FindByOrder(unsigned int num);
|
||||
private:
|
||||
List<CExtension *> m_Libs;
|
||||
};
|
||||
|
||||
extern CExtensionManager g_Extensions;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_EXTENSION_SYSTEM_H_
|
||||
@@ -0,0 +1,737 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "ForwardSys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "ShareSys.h"
|
||||
#include "DebugReporter.h"
|
||||
|
||||
CForwardManager g_Forwards;
|
||||
|
||||
/**
|
||||
* Genesis turns to its source, reduction occurs stepwise although the essence is all one.
|
||||
* End of line. FTL system check.
|
||||
*
|
||||
* :TODO: WHAT NEEDS TO BE TESTED IN THIS BEAST
|
||||
* VARARG FUNCTIONS:
|
||||
* - Pushing no varargs
|
||||
*/
|
||||
|
||||
// :TODO: IMPORTANT!!! The result pointer arg in the execute function maybe invalid if the forward fails
|
||||
// so later evaluation of this result may cause problems on higher levels of abstraction. DOCUMENT OR FIX ALL FORWARDS!
|
||||
|
||||
CForwardManager::~CForwardManager()
|
||||
{
|
||||
CStack<CForward *>::iterator iter;
|
||||
for (iter=m_FreeForwards.begin(); iter!=m_FreeForwards.end(); iter++)
|
||||
{
|
||||
delete (*iter);
|
||||
}
|
||||
m_FreeForwards.popall();
|
||||
}
|
||||
|
||||
void CForwardManager::OnSourceModAllInitialized()
|
||||
{
|
||||
g_PluginSys.AddPluginsListener(this);
|
||||
g_ShareSys.AddInterface(NULL, this);
|
||||
}
|
||||
|
||||
IForward *CForwardManager::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (fwd)
|
||||
{
|
||||
g_PluginSys.AddFunctionsToForward(name, fwd);
|
||||
|
||||
m_managed.push_back(fwd);
|
||||
}
|
||||
|
||||
return fwd;
|
||||
}
|
||||
|
||||
IChangeableForward *CForwardManager::CreateForwardEx(const char *name, ExecType et, int num_params, const ParamType *types, ...)
|
||||
{
|
||||
CForward *fwd;
|
||||
va_list ap;
|
||||
va_start(ap, types);
|
||||
|
||||
fwd = CForward::CreateForward(name, et, num_params, types, ap);
|
||||
|
||||
va_end(ap);
|
||||
|
||||
if (fwd)
|
||||
{
|
||||
m_unmanaged.push_back(fwd);
|
||||
}
|
||||
|
||||
return fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginLoaded(IPlugin *plugin)
|
||||
{
|
||||
/* Attach any globally managed forwards */
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
IPluginFunction *pFunc = plugin->GetBaseContext()->GetFunctionByName(fwd->GetForwardName());
|
||||
if (pFunc)
|
||||
{
|
||||
fwd->AddFunction(pFunc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginUnloaded(IPlugin *plugin)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
fwd->RemoveFunctionsOfPlugin(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
IForward *CForwardManager::FindForward(const char *name, IChangeableForward **ifchng)
|
||||
{
|
||||
List<CForward *>::iterator iter;
|
||||
CForward *fwd;
|
||||
|
||||
for (iter=m_managed.begin(); iter!=m_managed.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
for (iter=m_unmanaged.begin(); iter!=m_unmanaged.end(); iter++)
|
||||
{
|
||||
fwd = (*iter);
|
||||
if (strcmp(fwd->GetForwardName(), name) == 0)
|
||||
{
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = fwd;
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
}
|
||||
|
||||
if (ifchng)
|
||||
{
|
||||
*ifchng = NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CForwardManager::ReleaseForward(IForward *forward)
|
||||
{
|
||||
ForwardFree(static_cast<CForward *>(forward));
|
||||
}
|
||||
|
||||
void CForwardManager::ForwardFree(CForward *fwd)
|
||||
{
|
||||
if (fwd == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_FreeForwards.push(fwd);
|
||||
m_managed.remove(fwd);
|
||||
}
|
||||
|
||||
CForward *CForwardManager::ForwardMake()
|
||||
{
|
||||
CForward *fwd;
|
||||
if (m_FreeForwards.empty())
|
||||
{
|
||||
fwd = new CForward;
|
||||
} else {
|
||||
fwd = m_FreeForwards.front();
|
||||
m_FreeForwards.pop();
|
||||
}
|
||||
return fwd;
|
||||
}
|
||||
|
||||
void CForwardManager::OnPluginPauseChange(IPlugin *plugin, bool paused)
|
||||
{
|
||||
/* No longer used */
|
||||
}
|
||||
|
||||
/*************************************
|
||||
* ACTUAL FORWARD API IMPLEMENTATION *
|
||||
*************************************/
|
||||
|
||||
CForward *CForward::CreateForward(const char *name, ExecType et, unsigned int num_params, const ParamType *types, va_list ap)
|
||||
{
|
||||
ParamType _types[SP_MAX_EXEC_PARAMS];
|
||||
|
||||
if (num_params > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (types == NULL && num_params)
|
||||
{
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
_types[i] = (ParamType)va_arg(ap, int);
|
||||
if (_types[i] == Param_VarArgs && (i != num_params - 1))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
types = _types;
|
||||
} else {
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
_types[i] = types[i];
|
||||
if (types[i] == Param_VarArgs && (i != num_params - 1))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* First parameter can never be varargs */
|
||||
if (num_params && _types[0] == Param_VarArgs)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CForward *pForward = g_Forwards.ForwardMake();
|
||||
pForward->m_curparam = 0;
|
||||
pForward->m_ExecType = et;
|
||||
snprintf(pForward->m_name, FORWARDS_NAME_MAX, "%s", name ? name : "");
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
pForward->m_types[i] = _types[i];
|
||||
}
|
||||
|
||||
if (num_params && _types[num_params-1] == Param_VarArgs)
|
||||
{
|
||||
pForward->m_varargs = num_params--;
|
||||
} else {
|
||||
pForward->m_varargs = false;
|
||||
}
|
||||
|
||||
pForward->m_numparams = num_params;
|
||||
pForward->m_errstate = SP_ERROR_NONE;
|
||||
|
||||
pForward->m_functions.clear();
|
||||
|
||||
return pForward;
|
||||
}
|
||||
|
||||
int CForward::Execute(cell_t *result, IForwardFilter *filter)
|
||||
{
|
||||
if (m_errstate)
|
||||
{
|
||||
int err = m_errstate;
|
||||
Cancel();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (filter)
|
||||
{
|
||||
filter->OnExecuteBegin();
|
||||
}
|
||||
|
||||
FuncIter iter = m_functions.begin();
|
||||
IPluginFunction *func;
|
||||
cell_t cur_result = 0;
|
||||
cell_t high_result = 0;
|
||||
int err;
|
||||
unsigned int failed=0, success=0;
|
||||
unsigned int num_params = m_curparam;
|
||||
FwdParamInfo temp_info[SP_MAX_EXEC_PARAMS];
|
||||
FwdParamInfo *param;
|
||||
ParamType type;
|
||||
|
||||
/* Save local, reset */
|
||||
memcpy(temp_info, m_params, sizeof(m_params));
|
||||
m_curparam = 0;
|
||||
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
{
|
||||
func = (*iter);
|
||||
|
||||
for (unsigned int i=0; i<num_params; i++)
|
||||
{
|
||||
int err = SP_ERROR_PARAM;
|
||||
param = &temp_info[i];
|
||||
if (i >= m_numparams || m_types[i] == Param_Any)
|
||||
{
|
||||
type = param->pushedas;
|
||||
} else {
|
||||
type = m_types[i];
|
||||
}
|
||||
if ((i >= m_numparams) || (type & SP_PARAMFLAG_BYREF))
|
||||
{
|
||||
/* If we're byref or we're vararg, we always push everything by ref.
|
||||
* Even if they're byval, we must push them byref.
|
||||
*/
|
||||
if (type == Param_String)
|
||||
{
|
||||
err = func->PushStringEx((char *)param->byref.orig_addr, param->byref.cells, param->byref.sz_flags, param->byref.flags);
|
||||
} else if (type == Param_Float || type == Param_Cell) {
|
||||
err = func->PushCellByRef(¶m->val);
|
||||
} else {
|
||||
err = func->PushArray(param->byref.orig_addr, param->byref.cells, param->byref.flags);
|
||||
assert(type == Param_Array || type == Param_FloatByRef || type == Param_CellByRef);
|
||||
}
|
||||
} else {
|
||||
/* If we're not byref or not vararg, our job is a bit easier. */
|
||||
assert(type == Param_Cell || type == Param_Float);
|
||||
err = func->PushCell(param->val);
|
||||
}
|
||||
if (err != SP_ERROR_NONE)
|
||||
{
|
||||
if (!filter || !filter->OnErrorReport(this, func, err))
|
||||
{
|
||||
g_DbgReporter.GenerateError(func->GetParentContext(),
|
||||
func->GetFunctionID(),
|
||||
err,
|
||||
"Failed to push parameter while executing forward");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the function and deal with the return value. */
|
||||
if ((err=func->Execute(&cur_result)) != SP_ERROR_NONE)
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
filter->OnErrorReport(this, func, err);
|
||||
}
|
||||
failed++;
|
||||
} else {
|
||||
success++;
|
||||
switch (m_ExecType)
|
||||
{
|
||||
case ET_Event:
|
||||
{
|
||||
if (cur_result > high_result)
|
||||
{
|
||||
high_result = cur_result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_Hook:
|
||||
{
|
||||
if (cur_result > high_result)
|
||||
{
|
||||
high_result = cur_result;
|
||||
if ((ResultType)high_result == Pl_Stop)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ET_Custom:
|
||||
{
|
||||
if (filter)
|
||||
{
|
||||
if (filter->OnFunctionReturn(this, func, &cur_result) == Pl_Stop)
|
||||
{
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
if (success)
|
||||
{
|
||||
if (m_ExecType == ET_Event || m_ExecType == ET_Hook)
|
||||
{
|
||||
cur_result = high_result;
|
||||
} else if (m_ExecType == ET_Ignore) {
|
||||
cur_result = 0;
|
||||
}
|
||||
if (result)
|
||||
{
|
||||
*result = cur_result;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter)
|
||||
{
|
||||
filter->OnExecuteEnd(&cur_result, success, failed);
|
||||
}
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushCell(cell_t cell)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Cell;
|
||||
} else if (m_types[m_curparam] != Param_Cell) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Cell;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].val = cell;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushFloat(float number)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Float;
|
||||
} else if (m_types[m_curparam] != Param_Float) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Float;
|
||||
}
|
||||
|
||||
m_params[m_curparam++].val = *(cell_t *)&number;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushCellByRef(cell_t *cell, int flags)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_CellByRef;
|
||||
} else if (m_types[m_curparam] != Param_CellByRef) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_CellByRef;
|
||||
}
|
||||
|
||||
_Int_PushArray(cell, 1, flags);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushFloatByRef(float *num, int flags)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_FloatByRef;
|
||||
} else if (m_types[m_curparam] != Param_FloatByRef) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_numparams > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_FloatByRef;
|
||||
}
|
||||
|
||||
_Int_PushArray((cell_t *)num, 1, flags);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::_Int_PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
{
|
||||
m_params[m_curparam].byref.cells = cells;
|
||||
m_params[m_curparam].byref.flags = flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
}
|
||||
|
||||
int CForward::PushArray(cell_t *inarray, unsigned int cells, int flags)
|
||||
{
|
||||
/* We don't allow this here */
|
||||
if (!inarray)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
} else if (m_types[m_curparam] != Param_Array) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_Array;
|
||||
}
|
||||
|
||||
_Int_PushArray(inarray, cells, flags);
|
||||
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::_Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags)
|
||||
{
|
||||
m_params[m_curparam].byref.cells = cells; /* Notice this contains the char count not cell count */
|
||||
m_params[m_curparam].byref.flags = cp_flags;
|
||||
m_params[m_curparam].byref.orig_addr = inarray;
|
||||
m_params[m_curparam].byref.sz_flags = sz_flags;
|
||||
}
|
||||
|
||||
int CForward::PushString(const char *string)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
} else if (m_types[m_curparam] != Param_String) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
_Int_PushString((cell_t *)string, strlen(string)+1, SM_PARAM_STRING_COPY, 0);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
int CForward::PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags)
|
||||
{
|
||||
if (m_curparam < m_numparams)
|
||||
{
|
||||
if (m_types[m_curparam] == Param_Any)
|
||||
{
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
} else if (m_types[m_curparam] != Param_String) {
|
||||
return SetError(SP_ERROR_PARAM);
|
||||
}
|
||||
} else {
|
||||
if (!m_varargs || m_curparam > SP_MAX_EXEC_PARAMS)
|
||||
{
|
||||
return SetError(SP_ERROR_PARAMS_MAX);
|
||||
}
|
||||
m_params[m_curparam].pushedas = Param_String;
|
||||
}
|
||||
|
||||
_Int_PushString((cell_t *)buffer, length, sz_flags, cp_flags);
|
||||
m_curparam++;
|
||||
|
||||
return SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
void CForward::Cancel()
|
||||
{
|
||||
if (!m_curparam)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_curparam = 0;
|
||||
m_errstate = SP_ERROR_NONE;
|
||||
}
|
||||
|
||||
bool CForward::AddFunction(IPluginContext *pContext, funcid_t index)
|
||||
{
|
||||
IPluginFunction *pFunc = pContext->GetFunctionById(index);
|
||||
|
||||
if (!pFunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return AddFunction(pFunc);
|
||||
}
|
||||
|
||||
bool CForward::RemoveFunction(IPluginContext *pContext, funcid_t index)
|
||||
{
|
||||
IPluginFunction *pFunc = pContext->GetFunctionById(index);
|
||||
|
||||
if (!pFunc)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return RemoveFunction(pFunc);
|
||||
}
|
||||
|
||||
bool CForward::RemoveFunction(IPluginFunction *func)
|
||||
{
|
||||
bool found = false;
|
||||
FuncIter iter;
|
||||
List<IPluginFunction *> *lst;
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
lst = &m_functions;
|
||||
} else {
|
||||
lst = &m_paused;
|
||||
}
|
||||
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end(); iter++)
|
||||
{
|
||||
if ((*iter) == func)
|
||||
{
|
||||
found = true;
|
||||
lst->erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel a call, if any */
|
||||
if (found || m_curparam)
|
||||
{
|
||||
func->Cancel();
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
unsigned int CForward::RemoveFunctionsOfPlugin(IPlugin *plugin)
|
||||
{
|
||||
FuncIter iter;
|
||||
IPluginFunction *func;
|
||||
unsigned int removed = 0;
|
||||
IPluginContext *pContext = plugin->GetBaseContext();
|
||||
for (iter=m_functions.begin(); iter!=m_functions.end();)
|
||||
{
|
||||
func = (*iter);
|
||||
if (func->GetParentContext() == pContext)
|
||||
{
|
||||
iter = m_functions.erase(iter);
|
||||
removed++;
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
bool CForward::AddFunction(IPluginFunction *func)
|
||||
{
|
||||
if (m_curparam)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (func->IsRunnable())
|
||||
{
|
||||
m_functions.push_back(func);
|
||||
} else {
|
||||
m_paused.push_back(func);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *CForward::GetForwardName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
unsigned int CForward::GetFunctionCount()
|
||||
{
|
||||
return m_functions.size();
|
||||
}
|
||||
|
||||
ExecType CForward::GetExecType()
|
||||
{
|
||||
return m_ExecType;
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
|
||||
#include <IForwardSys.h>
|
||||
#include <IPluginSys.h>
|
||||
#include "sm_globals.h"
|
||||
#include <sh_list.h>
|
||||
#include <sh_stack.h>
|
||||
#include "sourcemod.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
typedef List<IPluginFunction *>::iterator FuncIter;
|
||||
|
||||
//:TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX
|
||||
#define FORWARDS_NAME_MAX 64
|
||||
|
||||
struct ByrefInfo
|
||||
{
|
||||
unsigned int cells;
|
||||
cell_t *orig_addr;
|
||||
int flags;
|
||||
int sz_flags;
|
||||
};
|
||||
|
||||
struct FwdParamInfo
|
||||
{
|
||||
cell_t val;
|
||||
ByrefInfo byref;
|
||||
ParamType pushedas;
|
||||
};
|
||||
|
||||
class CForward : public IChangeableForward
|
||||
{
|
||||
public: //ICallable
|
||||
virtual int PushCell(cell_t cell);
|
||||
virtual int PushCellByRef(cell_t *cell, int flags);
|
||||
virtual int PushFloat(float number);
|
||||
virtual int PushFloatByRef(float *number, int flags);
|
||||
virtual int PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
virtual int PushString(const char *string);
|
||||
virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
|
||||
virtual void Cancel();
|
||||
public: //IForward
|
||||
virtual const char *GetForwardName();
|
||||
virtual unsigned int GetFunctionCount();
|
||||
virtual ExecType GetExecType();
|
||||
virtual int Execute(cell_t *result, IForwardFilter *filter);
|
||||
public: //IChangeableForward
|
||||
virtual bool RemoveFunction(IPluginFunction *func);
|
||||
virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
|
||||
virtual bool AddFunction(IPluginFunction *func);
|
||||
virtual bool AddFunction(IPluginContext *ctx, funcid_t index);
|
||||
virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
|
||||
public:
|
||||
static CForward *CreateForward(const char *name,
|
||||
ExecType et,
|
||||
unsigned int num_params,
|
||||
const ParamType *types,
|
||||
va_list ap);
|
||||
private:
|
||||
void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
|
||||
void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
|
||||
inline int SetError(int err)
|
||||
{
|
||||
m_errstate = err;
|
||||
return err;
|
||||
}
|
||||
protected:
|
||||
/* :TODO: I want a caching list type here.
|
||||
* Destroying these things and using new/delete for their members feels bad.
|
||||
*/
|
||||
mutable List<IPluginFunction *> m_functions;
|
||||
mutable List<IPluginFunction *> m_paused;
|
||||
|
||||
/* Type and name information */
|
||||
FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
|
||||
ParamType m_types[SP_MAX_EXEC_PARAMS];
|
||||
char m_name[FORWARDS_NAME_MAX+1];
|
||||
unsigned int m_numparams;
|
||||
unsigned int m_varargs;
|
||||
ExecType m_ExecType;
|
||||
|
||||
/* State information */
|
||||
unsigned int m_curparam;
|
||||
int m_errstate;
|
||||
};
|
||||
|
||||
class CForwardManager :
|
||||
public IForwardManager,
|
||||
public IPluginsListener,
|
||||
public SMGlobalClass
|
||||
{
|
||||
friend class CForward;
|
||||
public:
|
||||
~CForwardManager();
|
||||
public: //IForwardManager
|
||||
IForward *CreateForward(const char *name,
|
||||
ExecType et,
|
||||
unsigned int num_params,
|
||||
const ParamType *types,
|
||||
...);
|
||||
IChangeableForward *CreateForwardEx(const char *name,
|
||||
ExecType et,
|
||||
int num_params,
|
||||
const ParamType *types,
|
||||
...);
|
||||
IForward *FindForward(const char *name, IChangeableForward **ifchng);
|
||||
void ReleaseForward(IForward *forward);
|
||||
public: //IPluginsListener
|
||||
void OnPluginLoaded(IPlugin *plugin);
|
||||
void OnPluginUnloaded(IPlugin *plugin);
|
||||
void OnPluginPauseChange(IPlugin *plugin, bool paused);
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
protected:
|
||||
CForward *ForwardMake();
|
||||
void ForwardFree(CForward *fwd);
|
||||
private:
|
||||
CStack<CForward *> m_FreeForwards;
|
||||
List<CForward *> m_managed;
|
||||
List<CForward *> m_unmanaged;
|
||||
};
|
||||
|
||||
extern CForwardManager g_Forwards;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
|
||||
#include <IHandleSys.h>
|
||||
#include <stdio.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sourcemod.h"
|
||||
#include "sm_memtable.h"
|
||||
|
||||
#define HANDLESYS_MAX_HANDLES (1<<14)
|
||||
#define HANDLESYS_MAX_TYPES (1<<9)
|
||||
#define HANDLESYS_MAX_SUBTYPES 0xF
|
||||
#define HANDLESYS_SUBTYPE_MASK 0xF
|
||||
#define HANDLESYS_TYPEARRAY_SIZE (HANDLESYS_MAX_TYPES * (HANDLESYS_MAX_SUBTYPES + 1))
|
||||
#define HANDLESYS_MAX_SERIALS 0xFFFF
|
||||
#define HANDLESYS_SERIAL_MASK 0xFFFF0000
|
||||
#define HANDLESYS_HANDLE_MASK 0x0000FFFF
|
||||
|
||||
#define HANDLESYS_MEMUSAGE_MIN_VERSION 3
|
||||
|
||||
/**
|
||||
* The QHandle is a nasty structure that compacts the handle system into a big vector.
|
||||
* The members of the vector each encapsulate one Handle, however, they also act as nodes
|
||||
* in an inlined linked list and an inlined vector.
|
||||
*
|
||||
* The first of these lists is the 'freeID' list. Each node from 1 to N (where N
|
||||
* is the number of free nodes) has a 'freeID' that specifies a free Handle ID. This
|
||||
* is a quick hack to get around allocating a second base vector.
|
||||
*
|
||||
* The second vector is the identity linked list. An identity has its own handle, so
|
||||
* these handles are used as sentinel nodes for index linking. They point to the first and last
|
||||
* index into the handle array. Each subsequent Handle who is owned by that identity is mapped into
|
||||
* that list. This lets owning identities be unloaded in O(n) time.
|
||||
*
|
||||
* Eventually, there may be a third list for type chains.
|
||||
*/
|
||||
|
||||
enum HandleSet
|
||||
{
|
||||
HandleSet_None = 0,
|
||||
HandleSet_Used, /* The Handle is in use */
|
||||
HandleSet_Freed, /* The "master" Handle of a clone chain is freed */
|
||||
HandleSet_Identity, /* The Handle is a special identity */
|
||||
};
|
||||
|
||||
struct QHandle
|
||||
{
|
||||
HandleType_t type; /* Handle type */
|
||||
void *object; /* Unmaintained object pointer */
|
||||
IdentityToken_t *owner; /* Identity of object which owns this */
|
||||
unsigned int serial; /* Serial no. for sanity checking */
|
||||
unsigned int refcount; /* Reference count for safe destruction */
|
||||
unsigned int clone; /* If non-zero, this is our cloned parent index */
|
||||
HandleSet set; /* Information about the handle's state */
|
||||
bool access_special; /* Whether or not access rules are special or type-derived */
|
||||
bool is_destroying; /* Whether or not the handle is being destroyed */
|
||||
HandleAccess sec; /* Security rules */
|
||||
/* The following variables are unrelated to the Handle array, and used
|
||||
* as an inlined chain of information */
|
||||
unsigned int freeID; /* ID of a free handle in the free handle chain */
|
||||
/* Indexes into the handle array for owner membership.
|
||||
* For identity roots, these are treated as the head/tail. */
|
||||
unsigned int ch_prev; /* chained previous handle */
|
||||
unsigned int ch_next; /* chained next handle */
|
||||
};
|
||||
|
||||
struct QHandleType
|
||||
{
|
||||
IHandleTypeDispatch *dispatch;
|
||||
unsigned int freeID;
|
||||
unsigned int children;
|
||||
TypeAccess typeSec;
|
||||
HandleAccess hndlSec;
|
||||
unsigned int opened;
|
||||
int nameIdx;
|
||||
};
|
||||
|
||||
typedef void (HANDLE_REPORTER)(const char *str, ...);
|
||||
|
||||
class HandleSystem :
|
||||
public IHandleSys
|
||||
{
|
||||
friend HandleError IdentityHandle(IdentityToken_t *token, unsigned int *index);
|
||||
friend class ShareSystem;
|
||||
public:
|
||||
HandleSystem();
|
||||
~HandleSystem();
|
||||
public: //IHandleSystem
|
||||
|
||||
HandleType_t CreateType(const char *name,
|
||||
IHandleTypeDispatch *dispatch,
|
||||
HandleType_t parent,
|
||||
const TypeAccess *typeAccess,
|
||||
const HandleAccess *hndlAccess,
|
||||
IdentityToken_t *ident,
|
||||
HandleError *err);
|
||||
|
||||
bool RemoveType(HandleType_t type, IdentityToken_t *ident);
|
||||
|
||||
bool FindHandleType(const char *name, HandleType_t *type);
|
||||
|
||||
Handle_t CreateHandle(HandleType_t type,
|
||||
void *object,
|
||||
IdentityToken_t *owner,
|
||||
IdentityToken_t *ident,
|
||||
HandleError *err);
|
||||
|
||||
HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity);
|
||||
|
||||
HandleError CloneHandle(Handle_t handle,
|
||||
Handle_t *newhandle,
|
||||
IdentityToken_t *newOwner,
|
||||
const HandleSecurity *pSecurity);
|
||||
|
||||
HandleError ReadHandle(Handle_t handle,
|
||||
HandleType_t type,
|
||||
const HandleSecurity *pSecurity,
|
||||
void **object);
|
||||
|
||||
bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess);
|
||||
|
||||
bool TypeCheck(HandleType_t intype, HandleType_t outtype);
|
||||
|
||||
virtual Handle_t CreateHandleEx(HandleType_t type,
|
||||
void *object,
|
||||
const HandleSecurity *pSec,
|
||||
const HandleAccess *pAccess,
|
||||
HandleError *err);
|
||||
|
||||
void Dump(HANDLE_REPORTER rep);
|
||||
protected:
|
||||
/**
|
||||
* Decodes a handle with sanity and security checking.
|
||||
*/
|
||||
HandleError GetHandle(Handle_t handle,
|
||||
IdentityToken_t *ident,
|
||||
QHandle **pHandle,
|
||||
unsigned int *index,
|
||||
bool ignoreFree=false);
|
||||
|
||||
/**
|
||||
* Creates a basic handle and sets its reference count to 1.
|
||||
* Does not do any type or security checking.
|
||||
*/
|
||||
HandleError MakePrimHandle(HandleType_t type,
|
||||
QHandle **pHandle,
|
||||
unsigned int *index,
|
||||
HandleType_t *handle,
|
||||
IdentityToken_t *owner,
|
||||
bool identity=false);
|
||||
|
||||
/**
|
||||
* Frees a primitive handle. Does no object freeing, only reference count, bookkeeping,
|
||||
* and linked list maintenance.
|
||||
* If used on an Identity handle, destroys all Handles under that identity.
|
||||
*/
|
||||
void ReleasePrimHandle(unsigned int index);
|
||||
|
||||
/**
|
||||
* Sets the security owner of a type.
|
||||
*/
|
||||
void SetTypeSecurityOwner(HandleType_t type, IdentityToken_t *pToken);
|
||||
|
||||
/**
|
||||
* Helper function to check access rights.
|
||||
*/
|
||||
bool CheckAccess(QHandle *pHandle, HandleAccessRight right, const HandleSecurity *pSecurity);
|
||||
|
||||
/**
|
||||
* Some wrappers for internal functions, so we can pass indexes instead of encoded handles.
|
||||
*/
|
||||
HandleError FreeHandle(QHandle *pHandle, unsigned int index);
|
||||
void UnlinkHandleFromOwner(QHandle *pHandle, unsigned int index);
|
||||
HandleError CloneHandle(QHandle *pHandle, unsigned int index, Handle_t *newhandle, IdentityToken_t *newOwner);
|
||||
Handle_t CreateHandleInt(HandleType_t type, void *object, const HandleSecurity *pSec, HandleError *err, const HandleAccess *pAccess, bool identity);
|
||||
|
||||
bool TryAndFreeSomeHandles();
|
||||
HandleError TryAllocHandle(unsigned int *handle);
|
||||
private:
|
||||
QHandle *m_Handles;
|
||||
QHandleType *m_Types;
|
||||
Trie *m_TypeLookup;
|
||||
unsigned int m_TypeTail;
|
||||
unsigned int m_FreeTypes;
|
||||
unsigned int m_HandleTail;
|
||||
unsigned int m_FreeHandles;
|
||||
unsigned int m_HSerial;
|
||||
BaseStringTable *m_strtab;
|
||||
};
|
||||
|
||||
extern HandleSystem g_HandleSys;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_H_
|
||||
@@ -0,0 +1,441 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sm_platform.h>
|
||||
#include "sm_stringutil.h"
|
||||
#include "LibrarySys.h"
|
||||
|
||||
LibrarySystem g_LibSys;
|
||||
|
||||
CLibrary::~CLibrary()
|
||||
{
|
||||
if (m_lib)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
FreeLibrary(m_lib);
|
||||
#elif defined PLATFORM_POSIX
|
||||
dlclose(m_lib);
|
||||
#endif
|
||||
m_lib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CLibrary::CLibrary(LibraryHandle me)
|
||||
{
|
||||
m_lib = me;
|
||||
}
|
||||
|
||||
void CLibrary::CloseLibrary()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
void *CLibrary::GetSymbolAddress(const char *symname)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return GetProcAddress(m_lib, symname);
|
||||
#elif defined PLATFORM_POSIX
|
||||
return dlsym(m_lib, symname);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Directory Code **
|
||||
********************/
|
||||
|
||||
|
||||
CDirectory::CDirectory(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
char newpath[PLATFORM_MAX_PATH];
|
||||
snprintf(newpath, sizeof(newpath), "%s\\*.*", path);
|
||||
m_dir = FindFirstFileA(newpath, &m_fd);
|
||||
if (!IsValid())
|
||||
{
|
||||
m_fd.cFileName[0] = '\0';
|
||||
}
|
||||
#elif defined PLATFORM_POSIX
|
||||
m_dir = opendir(path);
|
||||
if (IsValid())
|
||||
{
|
||||
/* :TODO: we need to read past "." and ".."! */
|
||||
ep = readdir(m_dir);
|
||||
snprintf(m_origpath, PLATFORM_MAX_PATH, "%s", path);
|
||||
} else {
|
||||
ep = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CDirectory::~CDirectory()
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
FindClose(m_dir);
|
||||
#elif defined PLATFORM_POSIX
|
||||
closedir(m_dir);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CDirectory::NextEntry()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
if (FindNextFile(m_dir, &m_fd) == 0)
|
||||
{
|
||||
FindClose(m_dir);
|
||||
m_dir = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#elif defined PLATFORM_POSIX
|
||||
if ((ep=readdir(m_dir)) == NULL)
|
||||
{
|
||||
closedir(m_dir);
|
||||
m_dir = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CDirectory::IsEntryValid()
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
bool CDirectory::IsEntryDirectory()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return ((m_fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
|
||||
#elif defined PLATFORM_LINUX
|
||||
char temppath[PLATFORM_MAX_PATH];
|
||||
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
return g_LibSys.IsPathDirectory(temppath);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CDirectory::IsEntryFile()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return !(m_fd.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE));
|
||||
#elif defined PLATFORM_POSIX
|
||||
char temppath[PLATFORM_MAX_PATH];
|
||||
snprintf(temppath, sizeof(temppath), "%s/%s", m_origpath, GetEntryName());
|
||||
return g_LibSys.IsPathFile(temppath);
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *CDirectory::GetEntryName()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return m_fd.cFileName;
|
||||
#elif defined PLATFORM_LINUX
|
||||
return ep ? ep->d_name : "";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CDirectory::MoreFiles()
|
||||
{
|
||||
return IsValid();
|
||||
}
|
||||
|
||||
bool CDirectory::IsValid()
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return (m_dir != INVALID_HANDLE_VALUE);
|
||||
#elif defined PLATFORM_LINUX
|
||||
return (m_dir != NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*************************
|
||||
** Library System Code **
|
||||
*************************/
|
||||
|
||||
|
||||
bool LibrarySystem::PathExists(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributesA(path);
|
||||
|
||||
return (attr != INVALID_FILE_ATTRIBUTES);
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
|
||||
return (stat(path, &s) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LibrarySystem::IsPathFile(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif defined PLATFORM_LINUX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISREG(s.st_mode) ? true : false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool LibrarySystem::IsPathDirectory(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined PLATFORM_LINUX
|
||||
struct stat s;
|
||||
|
||||
if (stat(path, &s) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (S_ISDIR(s.st_mode))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IDirectory *LibrarySystem::OpenDirectory(const char *path)
|
||||
{
|
||||
CDirectory *dir = new CDirectory(path);
|
||||
|
||||
if (!dir->IsValid())
|
||||
{
|
||||
delete dir;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
void LibrarySystem::GetPlatformError(char *error, size_t maxlength)
|
||||
{
|
||||
if (error && maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPSTR)error,
|
||||
maxlength,
|
||||
NULL);
|
||||
#elif defined PLATFORM_POSIX
|
||||
UTIL_Format(error, maxlength, "%s", strerror(errno));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void LibrarySystem::GetLoaderError(char *buffer, size_t maxlength)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
GetPlatformError(buffer, maxlength);
|
||||
#elif defined PLATFORM_POSIX
|
||||
if (buffer != NULL && maxlength)
|
||||
{
|
||||
strncopy(buffer, dlerror(), maxlength);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LibrarySystem::CloseDirectory(IDirectory *dir)
|
||||
{
|
||||
delete dir;
|
||||
}
|
||||
|
||||
ILibrary *LibrarySystem::OpenLibrary(const char *path, char *error, size_t maxlength)
|
||||
{
|
||||
LibraryHandle lib;
|
||||
#if defined PLATFORM_WINDOWS
|
||||
lib = LoadLibraryA(path);
|
||||
#elif defined PLATFORM_POSIX
|
||||
lib = dlopen(path, RTLD_NOW);
|
||||
#endif
|
||||
|
||||
if (lib == NULL)
|
||||
{
|
||||
GetLoaderError(error, maxlength);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CLibrary(lib);
|
||||
}
|
||||
|
||||
size_t LibrarySystem::PathFormat(char *buffer, size_t len, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
size_t mylen = vsnprintf(buffer, len, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (mylen >= len)
|
||||
{
|
||||
mylen = len - 1;
|
||||
buffer[mylen] = '\0';
|
||||
}
|
||||
|
||||
for (size_t i=0; i<mylen; i++)
|
||||
{
|
||||
if (buffer[i] == PLATFORM_SEP_ALTCHAR)
|
||||
{
|
||||
buffer[i] = PLATFORM_SEP_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
return mylen;
|
||||
}
|
||||
|
||||
const char *LibrarySystem::GetFileExtension(const char *filename)
|
||||
{
|
||||
size_t len, end;
|
||||
|
||||
len = strlen(filename);
|
||||
|
||||
/* Minimum string length for filename with ext would be 3; example: a.a */
|
||||
if (len < 3)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
end = len - 1;
|
||||
|
||||
for (size_t i = end; i <= end; i--)
|
||||
{
|
||||
if (filename[i] == PLATFORM_SEP_CHAR || filename[i] == PLATFORM_SEP_ALTCHAR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (filename[i] == '.' && i != end && i != 0)
|
||||
{
|
||||
return &filename[++i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool LibrarySystem::CreateFolder(const char *path)
|
||||
{
|
||||
#if defined PLATFORM_WINDOWS
|
||||
return (mkdir(path) != -1);
|
||||
#elif defined PLATFORM_POSIX
|
||||
return (mkdir(path, 0775) != -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t LibrarySystem::GetFileFromPath(char *buffer, size_t maxlength, const char *path)
|
||||
{
|
||||
size_t length = strlen(path);
|
||||
|
||||
for (size_t i = length - 1;
|
||||
i >= 0 && i <= length - 1;
|
||||
i--)
|
||||
{
|
||||
if (path[i] == '/'
|
||||
#if defined PLATFORM_WINDOWS
|
||||
|| path[i] == '\\'
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return UTIL_Format(buffer, maxlength, "%s", &path[i+1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* We scanned and found no path separator */
|
||||
return UTIL_Format(buffer, maxlength, "%s", path);
|
||||
}
|
||||
|
||||
bool LibrarySystem::FileTime(const char *path, FileTimeType type, time_t *pTime)
|
||||
{
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
struct _stat s;
|
||||
if (_stat(path, &s) != 0)
|
||||
#elif defined PLATFORM_POSIX
|
||||
struct stat s;
|
||||
if (stat(path, &s) != 0)
|
||||
#endif
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type == FileTime_LastAccess)
|
||||
{
|
||||
*pTime = s.st_atime;
|
||||
}
|
||||
else if (type == FileTime_Created)
|
||||
{
|
||||
*pTime = s.st_ctime;
|
||||
}
|
||||
else if (type == FileTime_LastChange)
|
||||
{
|
||||
*pTime = s.st_mtime;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
|
||||
#define _INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
|
||||
|
||||
#include <ILibrarySys.h>
|
||||
#include "sm_platform.h"
|
||||
|
||||
using namespace SourceMod;
|
||||
|
||||
#if defined PLATFORM_WINDOWS
|
||||
typedef HMODULE LibraryHandle;
|
||||
#elif defined PLATFORM_POSIX
|
||||
typedef void * LibraryHandle;
|
||||
#endif
|
||||
|
||||
class CDirectory : public IDirectory
|
||||
{
|
||||
public:
|
||||
CDirectory(const char *path);
|
||||
~CDirectory();
|
||||
public:
|
||||
bool MoreFiles();
|
||||
void NextEntry();
|
||||
const char *GetEntryName();
|
||||
bool IsEntryDirectory();
|
||||
bool IsEntryFile();
|
||||
bool IsEntryValid();
|
||||
public:
|
||||
bool IsValid();
|
||||
private:
|
||||
#if defined PLATFORM_WINDOWS
|
||||
HANDLE m_dir;
|
||||
WIN32_FIND_DATAA m_fd;
|
||||
#elif defined PLATFORM_POSIX
|
||||
DIR *m_dir;
|
||||
struct dirent *ep;
|
||||
char m_origpath[PLATFORM_MAX_PATH];
|
||||
#endif
|
||||
};
|
||||
|
||||
class CLibrary : public ILibrary
|
||||
{
|
||||
public:
|
||||
CLibrary(LibraryHandle me);
|
||||
~CLibrary();
|
||||
public:
|
||||
void CloseLibrary();
|
||||
void *GetSymbolAddress(const char *symname);
|
||||
private:
|
||||
LibraryHandle m_lib;
|
||||
};
|
||||
|
||||
class LibrarySystem : public ILibrarySys
|
||||
{
|
||||
public:
|
||||
ILibrary *OpenLibrary(const char *path, char *error, size_t maxlength);
|
||||
IDirectory *OpenDirectory(const char *path);
|
||||
void CloseDirectory(IDirectory *dir);
|
||||
bool PathExists(const char *path);
|
||||
bool IsPathFile(const char *path);
|
||||
bool IsPathDirectory(const char *path);
|
||||
void GetPlatformError(char *error, size_t maxlength);
|
||||
size_t PathFormat(char *buffer, size_t len, const char *fmt, ...);
|
||||
const char *GetFileExtension(const char *filename);
|
||||
bool CreateFolder(const char *path);
|
||||
size_t GetFileFromPath(char *buffer, size_t maxlength, const char *path);
|
||||
bool FileTime(const char *path, FileTimeType type, time_t *pTime);
|
||||
void GetLoaderError(char *buffer, size_t maxlength);
|
||||
};
|
||||
|
||||
extern LibrarySystem g_LibSys;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_SYSTEM_LIBRARY_H_
|
||||
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "PluginInfoDatabase.h"
|
||||
#include "PluginSys.h"
|
||||
|
||||
void PluginSettings::Init()
|
||||
{
|
||||
name = -1;
|
||||
pause_val = false;
|
||||
type_val = PluginType_MapUpdated;
|
||||
optarray = -1;
|
||||
opts_num = 0;
|
||||
opts_size = 0;
|
||||
blockload_val = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* :TODO: write the logger, make these errors log instead of being static
|
||||
* NOTE: once we do that, we will have to change some code to ignore sections
|
||||
*/
|
||||
|
||||
CPluginInfoDatabase::CPluginInfoDatabase()
|
||||
{
|
||||
m_strtab = NULL;
|
||||
m_infodb_count = 0;
|
||||
m_infodb_size = 0;
|
||||
m_infodb = -1;
|
||||
}
|
||||
|
||||
CPluginInfoDatabase::~CPluginInfoDatabase()
|
||||
{
|
||||
delete m_strtab;
|
||||
}
|
||||
|
||||
void CPluginInfoDatabase::ReadSMC_ParseStart()
|
||||
{
|
||||
/* Create or reset our string table */
|
||||
if (m_strtab)
|
||||
{
|
||||
m_strtab->Reset();
|
||||
} else {
|
||||
m_strtab = new BaseStringTable(1024);
|
||||
}
|
||||
|
||||
/* Set our internal states to the beginning */
|
||||
in_plugins = false;
|
||||
cur_plugin = -1;
|
||||
in_options = false;
|
||||
m_infodb_size = 0;
|
||||
m_infodb_count = 0;
|
||||
m_infodb = -1;
|
||||
}
|
||||
|
||||
SMCResult CPluginInfoDatabase::MakeError(const char *fmt, ...)
|
||||
{
|
||||
char buffer[512];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
m_errmsg = m_strtab->AddString(buffer);
|
||||
|
||||
return SMCResult_HaltFail;
|
||||
}
|
||||
|
||||
unsigned int CPluginInfoDatabase::GetSettingsNum()
|
||||
{
|
||||
return m_infodb_count;
|
||||
}
|
||||
|
||||
PluginSettings *CPluginInfoDatabase::GetSettingsIfMatch(unsigned int index, const char *filename)
|
||||
{
|
||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
||||
int *table = (int *)memtab->GetAddress(m_infodb);
|
||||
|
||||
if (!table || index >= m_infodb_count)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PluginSettings *plugin = (PluginSettings *)memtab->GetAddress(table[index]);
|
||||
|
||||
const char *name = m_strtab->GetString(plugin->name);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!g_PluginSys.TestAliasMatch(name, filename))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return plugin;
|
||||
}
|
||||
|
||||
void CPluginInfoDatabase::GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val)
|
||||
{
|
||||
PluginOpts *table = (PluginOpts *)m_strtab->GetMemTable()->GetAddress(settings->optarray);
|
||||
if (!table)
|
||||
{
|
||||
*key = NULL;
|
||||
*val = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_num >= settings->opts_num)
|
||||
{
|
||||
*key = NULL;
|
||||
*val = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
*key = m_strtab->GetString(table[opt_num].key);
|
||||
*val = m_strtab->GetString(table[opt_num].val);
|
||||
}
|
||||
|
||||
SMCResult CPluginInfoDatabase::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
|
||||
{
|
||||
if (cur_plugin != -1)
|
||||
{
|
||||
PluginSettings *plugin = (PluginSettings *)m_strtab->GetMemTable()->GetAddress(cur_plugin);
|
||||
if (!in_options)
|
||||
{
|
||||
if (strcmp(key, "pause") == 0)
|
||||
{
|
||||
if (strcasecmp(value, "yes") == 0)
|
||||
{
|
||||
plugin->pause_val = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin->pause_val = false;
|
||||
}
|
||||
}
|
||||
else if (strcmp(key, "lifetime") == 0)
|
||||
{
|
||||
if (strcasecmp(value, "private") == 0)
|
||||
{
|
||||
plugin->type_val = PluginType_Private;
|
||||
}
|
||||
else if (strcasecmp(value, "mapsync") == 0)
|
||||
{
|
||||
plugin->type_val = PluginType_MapUpdated;
|
||||
}
|
||||
else if (strcasecmp(value, "maponly") == 0)
|
||||
{
|
||||
plugin->type_val = PluginType_MapOnly;
|
||||
}
|
||||
else if (strcasecmp(value, "global") == 0)
|
||||
{
|
||||
plugin->type_val = PluginType_Global;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeError("Unknown value for key \"lifetime\": \"%s\"", value);
|
||||
}
|
||||
}
|
||||
else if (strcmp(key, "blockload") == 0)
|
||||
{
|
||||
plugin->blockload_val = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeError("Unknown property key: \"%s\"", key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Cache every option, valid or not */
|
||||
int keyidx = m_strtab->AddString(key);
|
||||
int validx = m_strtab->AddString(value);
|
||||
PluginOpts *table;
|
||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
||||
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
|
||||
if (plugin->opts_num + 1 > plugin->opts_size)
|
||||
{
|
||||
unsigned int oldsize = plugin->opts_size;
|
||||
if (oldsize == 0)
|
||||
{
|
||||
//right now we don't have many
|
||||
plugin->opts_size = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
plugin->opts_size *= 2;
|
||||
}
|
||||
int newidx = memtab->CreateMem(plugin->opts_size * sizeof(PluginOpts), (void **)&table);
|
||||
/* in case it resized */
|
||||
plugin = (PluginSettings *)memtab->GetAddress(cur_plugin);
|
||||
if (plugin->optarray != -1)
|
||||
{
|
||||
void *oldtable = memtab->GetAddress(plugin->optarray);
|
||||
memcpy(table, oldtable, oldsize * sizeof(PluginOpts));
|
||||
}
|
||||
plugin->optarray = newidx;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = (PluginOpts *)memtab->GetAddress(plugin->optarray);
|
||||
}
|
||||
PluginOpts *opt = &table[plugin->opts_num++];
|
||||
opt->key = keyidx;
|
||||
opt->val = validx;
|
||||
}
|
||||
}
|
||||
else if (in_plugins)
|
||||
{
|
||||
return MakeError("Unknown property key: \"%s\"", key);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ignore anything we don't know about! */
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult CPluginInfoDatabase::ReadSMC_LeavingSection(const SMCStates *states)
|
||||
{
|
||||
if (in_plugins)
|
||||
{
|
||||
if (cur_plugin != -1)
|
||||
{
|
||||
if (in_options)
|
||||
{
|
||||
in_options = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the plugin is ending, add it to the table */
|
||||
BaseMemTable *memtab = m_strtab->GetMemTable();
|
||||
int *table;
|
||||
if (m_infodb_count + 1 > m_infodb_size)
|
||||
{
|
||||
unsigned int oldsize = m_infodb_size;
|
||||
if (!m_infodb_size)
|
||||
{
|
||||
m_infodb_size = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_infodb_size *= 2;
|
||||
}
|
||||
int newidx = memtab->CreateMem(m_infodb_size, (void **)&table);
|
||||
if (m_infodb != -1)
|
||||
{
|
||||
void *oldtable = (int *)memtab->GetAddress(m_infodb);
|
||||
memcpy(table, oldtable, oldsize * sizeof(int));
|
||||
}
|
||||
m_infodb = newidx;
|
||||
}
|
||||
else
|
||||
{
|
||||
table = (int *)memtab->GetAddress(m_infodb);
|
||||
}
|
||||
/* Assign to table and scrap the current plugin */
|
||||
table[m_infodb_count++] = cur_plugin;
|
||||
cur_plugin = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
in_plugins = false;
|
||||
}
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
SMCResult CPluginInfoDatabase::ReadSMC_NewSection(const SMCStates *states, const char *name)
|
||||
{
|
||||
if (!in_plugins)
|
||||
{
|
||||
/* If we're not in the main Plugins section, and we don't get it for the name, error out */
|
||||
if (strcmp(name, "Plugins") != 0)
|
||||
{
|
||||
return MakeError("Unknown root section: \"%s\"", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise set our states */
|
||||
in_plugins = true;
|
||||
cur_plugin = -1;
|
||||
in_options = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cur_plugin == -1)
|
||||
{
|
||||
/* If we get a plugin node and we don't have a current plugin, create a new one */
|
||||
PluginSettings *plugin;
|
||||
int i_name = m_strtab->AddString(name);
|
||||
cur_plugin = m_strtab->GetMemTable()->CreateMem(sizeof(PluginSettings), (void **)&plugin);
|
||||
plugin->Init();
|
||||
plugin->name = i_name;
|
||||
in_options = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!in_options && strcmp(name, "Options") == 0)
|
||||
{
|
||||
in_options = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MakeError("Unknown plugin sub-section: \"%s\"", name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return SMCResult_Continue;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
||||
#define _INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
||||
|
||||
/**
|
||||
* This file parses plugin_settings.cfg and stores the information in cached memory.
|
||||
* It provides simplistic abstraction to retrieving the info.
|
||||
* :TODO: currently untested
|
||||
*/
|
||||
|
||||
#include "sm_memtable.h"
|
||||
#include "ITextParsers.h"
|
||||
#include "IPluginSys.h"
|
||||
#include "sm_globals.h"
|
||||
|
||||
struct PluginOpts
|
||||
{
|
||||
int key;
|
||||
int val;
|
||||
};
|
||||
|
||||
struct PluginSettings
|
||||
{
|
||||
void Init();
|
||||
int name;
|
||||
bool pause_val;
|
||||
PluginType type_val;
|
||||
int optarray;
|
||||
size_t opts_num;
|
||||
size_t opts_size;
|
||||
bool blockload_val;
|
||||
};
|
||||
|
||||
class CPluginInfoDatabase : public ITextListener_SMC
|
||||
{
|
||||
public:
|
||||
CPluginInfoDatabase();
|
||||
~CPluginInfoDatabase();
|
||||
public: //ITextListener_SMC
|
||||
void ReadSMC_ParseStart();
|
||||
SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name);
|
||||
SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value);
|
||||
SMCResult ReadSMC_LeavingSection(const SMCStates *states);
|
||||
public:
|
||||
/**
|
||||
* Returns the number of plugin settings available.
|
||||
*/
|
||||
unsigned int GetSettingsNum();
|
||||
|
||||
/**
|
||||
* Given an index, returns the plugin settings block if the filename matches.
|
||||
* Otherwise, returns NULL.
|
||||
*/
|
||||
PluginSettings *GetSettingsIfMatch(unsigned int index, const char *filename);
|
||||
|
||||
/**
|
||||
* Given a plugin settings struct and an index,
|
||||
* returns the given JIT key/value option pair at that index.
|
||||
* If the input is invalid, key and val will be set to NULL.
|
||||
*/
|
||||
void GetOptionsForPlugin(PluginSettings *settings, unsigned int opt_num, const char **key, const char **val);
|
||||
private:
|
||||
SMCResult MakeError(const char *fmt, ...);
|
||||
private:
|
||||
BaseStringTable *m_strtab;
|
||||
int m_errmsg;
|
||||
bool in_plugins;
|
||||
bool in_options;
|
||||
int m_infodb;
|
||||
size_t m_infodb_count;
|
||||
size_t m_infodb_size;
|
||||
int cur_plugin;
|
||||
};
|
||||
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_CORE_SYSTEM_PLUGININFODATABASE_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,484 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <IPluginSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <IForwardSys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sh_stack.h>
|
||||
#include <sh_vector.h>
|
||||
#include <sh_string.h>
|
||||
#include "sm_globals.h"
|
||||
#include "vm/sp_vm_basecontext.h"
|
||||
#include "PluginInfoDatabase.h"
|
||||
#include "sm_trie.h"
|
||||
#include "sourcemod.h"
|
||||
#include <IRootConsoleMenu.h>
|
||||
#if defined ORANGEBOX_BUILD
|
||||
#include "convar_sm_ob.h"
|
||||
#else
|
||||
#include "convar_sm.h"
|
||||
#endif
|
||||
#include "ITranslator.h"
|
||||
#include "NativeOwner.h"
|
||||
#include "ShareSys.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
/**
|
||||
* NOTES:
|
||||
*
|
||||
* UPDATE 2008-03-11: These comments are horribly out of date. They paint a good overall
|
||||
* picture of how PluginSys works, but things like dependencies and fake natives have
|
||||
* complicated things quite a bit.
|
||||
*
|
||||
* Currently this system needs a lot of work but it's good skeletally. Plugin creation
|
||||
* is done without actually compiling anything. This is done by Load functions in the
|
||||
* manager. This will need a rewrite when we add context switching.
|
||||
*
|
||||
* The plugin object itself has a few things to note. The most important is that it stores
|
||||
* a table of function objects. The manager marshals allocation and freeing of these objects.
|
||||
* The plugin object can be in erroneous states, they are:
|
||||
* Plugin_Error --> Some error occurred any time during or after compilation.
|
||||
* This error can be cleared since the plugin itself is valid.
|
||||
* However, the state itself being set prevents any runtime action.
|
||||
* Plugin_BadLoad --> The plugin failed to load entirely and nothing can be done to save it.
|
||||
*
|
||||
* If a plugin fails to load externally, it is never added to the internal tracker. However,
|
||||
* plugins that failed to load from the internal loading mechanism are always tracked. This
|
||||
* allows users to see which automatically loaded plugins failed, and makes the interface a bit
|
||||
* more flexible.
|
||||
*
|
||||
* Once a plugin is compiled, it sets its own state to Plugin_Created. This state is still invalid
|
||||
* for execution. SourceMod is a two pass system, and even though the second pass is not implemented
|
||||
* yet, it is structured so Plugin_Created must be switched to Plugin_Running in the second pass. When
|
||||
* implemented, a Created plugin will be switched to Error in the second pass if it not loadable.
|
||||
*
|
||||
* The two pass loading mechanism is described below. Modules/natives are not implemented yet.
|
||||
* PASS ONE: All loadable plugins are found and have the following steps performed:
|
||||
* 1. Loading and compilation is attempted.
|
||||
* 2. If successful, all natives from Core are added.
|
||||
* 3. OnPluginLoad() is called.
|
||||
* 4. If failed, any user natives are scrapped and the process halts here.
|
||||
* 5. If successful, the plugin is ready for Pass 2.
|
||||
* INTERMEDIATE:
|
||||
* 1. All forced modules are loaded.
|
||||
* PASS TWO: All loaded plugins are found and have these steps performed:
|
||||
* 1. Any modules referenced in the plugin that are not already loaded, are loaded.
|
||||
* 2. If any module fails to load and the plugin requires it, load fails and jump to step 6.
|
||||
* 3. If any natives are unresolved, check if they are found in the user-natives pool.
|
||||
* 4. If yes, load succeeds. If not, natives are passed through a native acceptance filter.
|
||||
* 5. If the filter fails, the plugin is marked as failed.
|
||||
* 6. If the plugin has failed to load at this point, any dynamic natives it has added are scrapped.
|
||||
* Furthermore, any plugin that referenced these natives must now have pass 2 re-ran.
|
||||
* PASS THREE (not a real pass):
|
||||
* 7. Once all plugins are deemed to be loaded, OnPluginStart() is called
|
||||
*/
|
||||
|
||||
#define SM_CONTEXTVAR_MYSELF 0
|
||||
|
||||
struct ContextPair
|
||||
{
|
||||
ContextPair() : base(NULL), ctx(NULL), co(NULL)
|
||||
{
|
||||
};
|
||||
BaseContext *base;
|
||||
sp_context_t *ctx;
|
||||
ICompilation *co;
|
||||
IVirtualMachine *vm;
|
||||
};
|
||||
|
||||
enum LoadRes
|
||||
{
|
||||
LoadRes_Successful,
|
||||
LoadRes_AlreadyLoaded,
|
||||
LoadRes_Failure,
|
||||
LoadRes_NeverLoad
|
||||
};
|
||||
|
||||
struct AutoConfig
|
||||
{
|
||||
String autocfg;
|
||||
String folder;
|
||||
bool create;
|
||||
};
|
||||
|
||||
class CPlugin;
|
||||
|
||||
class CPlugin :
|
||||
public IPlugin,
|
||||
public CNativeOwner
|
||||
{
|
||||
friend class CPluginManager;
|
||||
friend class CFunction;
|
||||
public:
|
||||
CPlugin(const char *file);
|
||||
~CPlugin();
|
||||
public:
|
||||
PluginType GetType();
|
||||
SourcePawn::IPluginContext *GetBaseContext();
|
||||
sp_context_t *GetContext();
|
||||
const sm_plugininfo_t *GetPublicInfo();
|
||||
const char *GetFilename();
|
||||
bool IsDebugging();
|
||||
PluginStatus GetStatus();
|
||||
bool SetPauseState(bool paused);
|
||||
unsigned int GetSerial();
|
||||
const sp_plugin_t *GetPluginStructure();
|
||||
IdentityToken_t *GetIdentity();
|
||||
unsigned int CalcMemUsage();
|
||||
bool SetProperty(const char *prop, void *ptr);
|
||||
bool GetProperty(const char *prop, void **ptr, bool remove=false);
|
||||
void DropEverything();
|
||||
public:
|
||||
/**
|
||||
* Creates a plugin object with default values.
|
||||
* If an error buffer is specified, and an error occurs, the error will be copied to the buffer
|
||||
* and NULL will be returned.
|
||||
* If an error buffer is not specified, the error will be copied to an internal buffer and
|
||||
* a valid (but error-stated) CPlugin will be returned.
|
||||
*/
|
||||
static CPlugin *CreatePlugin(const char *file, char *error, size_t maxlength);
|
||||
public:
|
||||
/**
|
||||
* Starts the initial compilation of a plugin.
|
||||
* Returns false if another compilation exists or there is a current context set.
|
||||
*/
|
||||
ICompilation *StartMyCompile(IVirtualMachine *vm);
|
||||
/**
|
||||
* Finalizes a compilation. If error buffer is NULL, the error is saved locally.
|
||||
*/
|
||||
bool FinishMyCompile(char *error, size_t maxlength);
|
||||
void CancelMyCompile();
|
||||
|
||||
/**
|
||||
* Sets an error state on the plugin
|
||||
*/
|
||||
void SetErrorState(PluginStatus status, const char *error_fmt, ...);
|
||||
|
||||
/**
|
||||
* Initializes the plugin's identity information
|
||||
*/
|
||||
void InitIdentity();
|
||||
|
||||
/**
|
||||
* Calls the OnPluginLoad function, and sets any failed states if necessary.
|
||||
* NOTE: Valid pre-states are: Plugin_Created
|
||||
* NOTE: If validated, plugin state is changed to Plugin_Loaded
|
||||
*
|
||||
* If the error buffer is NULL, the error message is cached locally.
|
||||
*/
|
||||
bool Call_AskPluginLoad(char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Calls the OnPluginStart function.
|
||||
* NOTE: Valid pre-states are: Plugin_Created
|
||||
* NOTE: Post-state will be Plugin_Running
|
||||
*/
|
||||
void Call_OnPluginStart();
|
||||
|
||||
/**
|
||||
* Calls the OnPluginEnd function.
|
||||
*/
|
||||
void Call_OnPluginEnd();
|
||||
|
||||
/**
|
||||
* Calls the OnAllPluginsLoaded function.
|
||||
*/
|
||||
void Call_OnAllPluginsLoaded();
|
||||
|
||||
/**
|
||||
* Toggles debug mode in the plugin
|
||||
*/
|
||||
bool ToggleDebugMode(bool debug, char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Returns true if a plugin is usable.
|
||||
*/
|
||||
bool IsRunnable();
|
||||
|
||||
/**
|
||||
* Get languages info.
|
||||
*/
|
||||
IPhraseCollection *GetPhrases();
|
||||
public:
|
||||
/**
|
||||
* Returns the modification time during last plugin load.
|
||||
*/
|
||||
time_t GetTimeStamp();
|
||||
|
||||
/**
|
||||
* Returns the current modification time of the plugin file.
|
||||
*/
|
||||
time_t GetFileTimeStamp();
|
||||
|
||||
/**
|
||||
* Returns true if the plugin was running, but is now invalid.
|
||||
*/
|
||||
bool WasRunning();
|
||||
|
||||
Handle_t GetMyHandle();
|
||||
|
||||
bool AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
void AddConfig(bool autoCreate, const char *cfg, const char *folder);
|
||||
unsigned int GetConfigCount();
|
||||
AutoConfig *GetConfig(unsigned int i);
|
||||
inline void AddLibrary(const char *name)
|
||||
{
|
||||
m_Libraries.push_back(name);
|
||||
}
|
||||
void LibraryActions(bool dropping);
|
||||
protected:
|
||||
void UpdateInfo();
|
||||
void SetTimeStamp(time_t t);
|
||||
void DependencyDropped(CPlugin *pOwner);
|
||||
private:
|
||||
ContextPair m_ctx;
|
||||
PluginType m_type;
|
||||
char m_filename[PLATFORM_MAX_PATH];
|
||||
PluginStatus m_status;
|
||||
unsigned int m_serial;
|
||||
sm_plugininfo_t m_info;
|
||||
sp_plugin_t *m_plugin;
|
||||
char m_errormsg[256];
|
||||
time_t m_LastAccess;
|
||||
IdentityToken_t *m_ident;
|
||||
Handle_t m_handle;
|
||||
bool m_WasRunning;
|
||||
IPhraseCollection *m_pPhrases;
|
||||
List<String> m_RequiredLibs;
|
||||
List<String> m_Libraries;
|
||||
Trie *m_pProps;
|
||||
bool m_FakeNativesMissing;
|
||||
bool m_LibraryMissing;
|
||||
CVector<AutoConfig *> m_configs;
|
||||
bool m_bGotAllLoaded;
|
||||
int m_FileVersion;
|
||||
char m_DateTime[256];
|
||||
};
|
||||
|
||||
class CPluginManager :
|
||||
public IPluginManager,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch,
|
||||
public IRootConsoleCommand
|
||||
{
|
||||
friend class CPlugin;
|
||||
public:
|
||||
CPluginManager();
|
||||
~CPluginManager();
|
||||
public:
|
||||
/* Implements iterator class */
|
||||
class CPluginIterator : public IPluginIterator
|
||||
{
|
||||
public:
|
||||
CPluginIterator(List<CPlugin *> *mylist);
|
||||
virtual ~CPluginIterator();
|
||||
virtual bool MorePlugins();
|
||||
virtual IPlugin *GetPlugin();
|
||||
virtual void NextPlugin();
|
||||
void Release();
|
||||
public:
|
||||
void Reset();
|
||||
private:
|
||||
List<CPlugin *> *mylist;
|
||||
List<CPlugin *>::iterator current;
|
||||
};
|
||||
friend class CPluginManager::CPluginIterator;
|
||||
public: //IPluginManager
|
||||
IPlugin *LoadPlugin(const char *path,
|
||||
bool debug,
|
||||
PluginType type,
|
||||
char error[],
|
||||
size_t maxlength,
|
||||
bool *wasloaded);
|
||||
bool UnloadPlugin(IPlugin *plugin);
|
||||
IPlugin *FindPluginByContext(const sp_context_t *ctx);
|
||||
unsigned int GetPluginCount();
|
||||
IPluginIterator *GetPluginIterator();
|
||||
void AddPluginsListener(IPluginsListener *listener);
|
||||
void RemovePluginsListener(IPluginsListener *listener);
|
||||
public: //SMGlobalClass
|
||||
void OnSourceModAllInitialized();
|
||||
void OnSourceModShutdown();
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
bool GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize);
|
||||
public: //IRootConsoleCommand
|
||||
void OnRootConsoleCommand(const char *cmdname, const CCommand &command);
|
||||
public:
|
||||
/**
|
||||
* Loads all plugins not yet loaded
|
||||
*/
|
||||
void LoadAll_FirstPass(const char *config, const char *basedir);
|
||||
|
||||
/**
|
||||
* Runs the second loading pass for all plugins
|
||||
*/
|
||||
void LoadAll_SecondPass();
|
||||
|
||||
/**
|
||||
* Tests a plugin file mask against a local folder.
|
||||
* The alias is searched backwards from localdir - i.e., given this input:
|
||||
* csdm/ban csdm/ban
|
||||
* ban csdm/ban
|
||||
* csdm/ban optional/csdm/ban
|
||||
* All of these will return true for an alias match.
|
||||
* Wildcards are allowed in the filename.
|
||||
*/
|
||||
bool TestAliasMatch(const char *alias, const char *localdir);
|
||||
|
||||
/**
|
||||
* Returns whether anything loaded will be a late load.
|
||||
*/
|
||||
bool IsLateLoadTime() const;
|
||||
|
||||
/**
|
||||
* Converts a Handle to an IPlugin if possible.
|
||||
*/
|
||||
IPlugin *PluginFromHandle(Handle_t handle, HandleError *err);
|
||||
|
||||
/**
|
||||
* Finds a plugin based on its index. (starts on index 1)
|
||||
*/
|
||||
CPlugin *GetPluginByOrder(int num);
|
||||
|
||||
int GetOrderOfPlugin(IPlugin *pl);
|
||||
|
||||
/**
|
||||
* Internal version of FindPluginByContext()
|
||||
*/
|
||||
inline CPlugin *GetPluginByCtx(const sp_context_t *ctx)
|
||||
{
|
||||
return reinterpret_cast<CPlugin *>(ctx->user[SM_CONTEXTVAR_MYSELF]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets status text for a status code
|
||||
*/
|
||||
const char *GetStatusText(PluginStatus status);
|
||||
|
||||
/**
|
||||
* Reload or update plugins on level shutdown.
|
||||
*/
|
||||
void ReloadOrUnloadPlugins();
|
||||
|
||||
/**
|
||||
* Add public functions from all running or paused
|
||||
* plugins to the specified forward if the names match.
|
||||
*/
|
||||
void AddFunctionsToForward(const char *name, IChangeableForward *pForward);
|
||||
|
||||
/**
|
||||
* Iterates through plugins to call OnAllPluginsLoaded.
|
||||
*/
|
||||
void AllPluginsLoaded();
|
||||
|
||||
CPlugin *GetPluginFromIdentity(IdentityToken_t *pToken);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void OnLibraryAction(const char *lib, bool is_a_plugin, bool drop);
|
||||
|
||||
bool LibraryExists(const char *lib);
|
||||
|
||||
bool ReloadPlugin(CPlugin *pl);
|
||||
|
||||
void UnloadAll();
|
||||
|
||||
CPlugin *FindPluginByConsoleArg(const char *arg);
|
||||
private:
|
||||
LoadRes _LoadPlugin(CPlugin **pPlugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength);
|
||||
|
||||
void LoadAutoPlugin(const char *plugin);
|
||||
|
||||
/**
|
||||
* Recursively loads all plugins in the given directory.
|
||||
*/
|
||||
void LoadPluginsFromDir(const char *basedir, const char *localdir);
|
||||
|
||||
/**
|
||||
* Adds a plugin object. This is wrapped by LoadPlugin functions.
|
||||
*/
|
||||
void AddPlugin(CPlugin *pPlugin);
|
||||
|
||||
/**
|
||||
* Runs the second loading pass on a plugin.
|
||||
*/
|
||||
bool RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Runs an extension pass on a plugin.
|
||||
*/
|
||||
bool LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength);
|
||||
|
||||
/**
|
||||
* Manages required natives.
|
||||
*/
|
||||
bool FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength);
|
||||
|
||||
void _SetPauseState(CPlugin *pPlugin, bool pause);
|
||||
protected:
|
||||
/**
|
||||
* Caching internal objects
|
||||
*/
|
||||
void ReleaseIterator(CPluginIterator *iter);
|
||||
public:
|
||||
inline IdentityToken_t *GetIdentity()
|
||||
{
|
||||
return m_MyIdent;
|
||||
}
|
||||
private:
|
||||
void TryRefreshDependencies(CPlugin *pOther);
|
||||
private:
|
||||
List<IPluginsListener *> m_listeners;
|
||||
List<CPlugin *> m_plugins;
|
||||
CStack<CPluginManager::CPluginIterator *> m_iters;
|
||||
CPluginInfoDatabase m_PluginInfo;
|
||||
Trie *m_LoadLookup;
|
||||
bool m_AllPluginsLoaded;
|
||||
IdentityToken_t *m_MyIdent;
|
||||
|
||||
/* Dynamic native stuff */
|
||||
List<FakeNative *> m_Natives;
|
||||
|
||||
bool m_LoadingLocked;
|
||||
};
|
||||
|
||||
extern CPluginManager g_PluginSys;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_PLUGINSYSTEM_H_
|
||||
@@ -0,0 +1,515 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#include "ShareSys.h"
|
||||
#include "HandleSys.h"
|
||||
#include "ExtensionSys.h"
|
||||
#include "LibrarySys.h"
|
||||
#include "PluginSys.h"
|
||||
#include "sm_stringutil.h"
|
||||
|
||||
ShareSystem g_ShareSys;
|
||||
static unsigned int g_mark_serial = 0;
|
||||
|
||||
ShareSystem::ShareSystem()
|
||||
{
|
||||
m_IdentRoot.ident = 0;
|
||||
m_TypeRoot = 0;
|
||||
m_IfaceType = 0;
|
||||
m_CoreType = 0;
|
||||
}
|
||||
|
||||
IdentityToken_t *ShareSystem::CreateCoreIdentity()
|
||||
{
|
||||
if (!m_CoreType)
|
||||
{
|
||||
m_CoreType = CreateIdentType("CORE");
|
||||
}
|
||||
|
||||
return CreateIdentity(m_CoreType, this);
|
||||
}
|
||||
|
||||
void ShareSystem::Initialize()
|
||||
{
|
||||
TypeAccess sec;
|
||||
|
||||
g_HandleSys.InitAccessDefaults(&sec, NULL);
|
||||
sec.ident = GetIdentRoot();
|
||||
|
||||
m_TypeRoot = g_HandleSys.CreateType("Identity", this, 0, &sec, NULL, NULL, NULL);
|
||||
m_IfaceType = g_HandleSys.CreateType("Interface", this, 0, NULL, NULL, GetIdentRoot(), NULL);
|
||||
|
||||
/* Initialize our static identity handle */
|
||||
m_IdentRoot.ident = g_HandleSys.CreateHandle(m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
|
||||
|
||||
/* Add the Handle System and others... they are too innocent and pure to do it themselves */
|
||||
AddInterface(NULL, &g_HandleSys);
|
||||
AddInterface(NULL, &g_LibSys);
|
||||
}
|
||||
|
||||
void ShareSystem::OnSourceModShutdown()
|
||||
{
|
||||
if (m_CoreType)
|
||||
{
|
||||
g_HandleSys.RemoveType(m_CoreType, GetIdentRoot());
|
||||
}
|
||||
|
||||
g_HandleSys.RemoveType(m_IfaceType, GetIdentRoot());
|
||||
g_HandleSys.RemoveType(m_TypeRoot, GetIdentRoot());
|
||||
}
|
||||
|
||||
IdentityType_t ShareSystem::FindIdentType(const char *name)
|
||||
{
|
||||
HandleType_t type;
|
||||
|
||||
if (g_HandleSys.FindHandleType(name, &type))
|
||||
{
|
||||
if (g_HandleSys.TypeCheck(type, m_TypeRoot))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IdentityType_t ShareSystem::CreateIdentType(const char *name)
|
||||
{
|
||||
if (!m_TypeRoot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return g_HandleSys.CreateType(name, this, m_TypeRoot, NULL, NULL, GetIdentRoot(), NULL);
|
||||
}
|
||||
|
||||
void ShareSystem::OnHandleDestroy(HandleType_t type, void *object)
|
||||
{
|
||||
/* THIS WILL NEVER BE CALLED FOR ANYTHING WITH THE IDENTITY TYPE */
|
||||
}
|
||||
|
||||
IdentityToken_t *ShareSystem::CreateIdentity(IdentityType_t type, void *ptr)
|
||||
{
|
||||
if (!m_TypeRoot)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* :TODO: Cache? */
|
||||
IdentityToken_t *pToken = new IdentityToken_t;
|
||||
|
||||
HandleSecurity sec;
|
||||
sec.pOwner = sec.pIdentity = GetIdentRoot();
|
||||
|
||||
pToken->ident = g_HandleSys.CreateHandleInt(type, NULL, &sec, NULL, NULL, true);
|
||||
pToken->ptr = ptr;
|
||||
pToken->type = type;
|
||||
|
||||
return pToken;
|
||||
}
|
||||
|
||||
bool ShareSystem::AddInterface(IExtension *myself, SMInterface *iface)
|
||||
{
|
||||
if (!iface)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
IfaceInfo info;
|
||||
|
||||
info.owner = myself;
|
||||
info.iface = iface;
|
||||
|
||||
m_Interfaces.push_back(info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShareSystem::RequestInterface(const char *iface_name,
|
||||
unsigned int iface_vers,
|
||||
IExtension *myself,
|
||||
SMInterface **pIface)
|
||||
{
|
||||
/* See if the interface exists */
|
||||
List<IfaceInfo>::iterator iter;
|
||||
SMInterface *iface;
|
||||
IExtension *iface_owner;
|
||||
bool found = false;
|
||||
for (iter=m_Interfaces.begin(); iter!=m_Interfaces.end(); iter++)
|
||||
{
|
||||
IfaceInfo &info = (*iter);
|
||||
iface = info.iface;
|
||||
if (strcmp(iface->GetInterfaceName(), iface_name) == 0)
|
||||
{
|
||||
if (iface->GetInterfaceVersion() == iface_vers
|
||||
|| iface->IsVersionCompatible(iface_vers))
|
||||
{
|
||||
iface_owner = info.owner;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add a dependency node */
|
||||
if (iface_owner)
|
||||
{
|
||||
IfaceInfo info;
|
||||
info.iface = iface;
|
||||
info.owner = iface_owner;
|
||||
g_Extensions.BindDependency(myself, &info);
|
||||
}
|
||||
|
||||
if (pIface)
|
||||
{
|
||||
*pIface = iface;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShareSystem::AddNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
CNativeOwner *pOwner;
|
||||
|
||||
pOwner = g_Extensions.GetNativeOwner(myself);
|
||||
|
||||
pOwner->AddNatives(natives);
|
||||
}
|
||||
|
||||
void ShareSystem::DestroyIdentity(IdentityToken_t *identity)
|
||||
{
|
||||
HandleSecurity sec;
|
||||
|
||||
sec.pOwner = GetIdentRoot();
|
||||
sec.pIdentity = GetIdentRoot();
|
||||
|
||||
g_HandleSys.FreeHandle(identity->ident, &sec);
|
||||
delete identity;
|
||||
}
|
||||
|
||||
void ShareSystem::DestroyIdentType(IdentityType_t type)
|
||||
{
|
||||
g_HandleSys.RemoveType(type, GetIdentRoot());
|
||||
}
|
||||
|
||||
void ShareSystem::RemoveInterfaces(IExtension *pExtension)
|
||||
{
|
||||
List<IfaceInfo>::iterator iter = m_Interfaces.begin();
|
||||
|
||||
while (iter != m_Interfaces.end())
|
||||
{
|
||||
if ((*iter).owner == pExtension)
|
||||
{
|
||||
iter = m_Interfaces.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareSystem::AddDependency(IExtension *myself, const char *filename, bool require, bool autoload)
|
||||
{
|
||||
g_Extensions.AddDependency(myself, filename, require, autoload);
|
||||
}
|
||||
|
||||
void ShareSystem::RegisterLibrary(IExtension *myself, const char *name)
|
||||
{
|
||||
g_Extensions.AddLibrary(myself, name);
|
||||
}
|
||||
|
||||
void ShareSystem::OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives)
|
||||
{
|
||||
unsigned int i;
|
||||
NativeEntry *pEntry;
|
||||
CNativeOwner *pOwner;
|
||||
|
||||
pOwner = g_Extensions.GetNativeOwner(myself);
|
||||
|
||||
for (i = 0; natives[i].func != NULL && natives[i].name != NULL; i++)
|
||||
{
|
||||
if ((pEntry = FindNative(natives[i].name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pEntry->replacement.owner != NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now it's safe to add the override */
|
||||
pEntry->replacement.func = natives[i].func;
|
||||
pEntry->replacement.owner = pOwner;
|
||||
pOwner->AddReplacedNative(pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::FindNative(const char *name)
|
||||
{
|
||||
NativeEntry **ppEntry;
|
||||
|
||||
if ((ppEntry = m_NtvCache.retrieve(name)) == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return *ppEntry;
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
sp_native_t *native;
|
||||
uint32_t i, native_count;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = pPlugin->GetBaseContext();
|
||||
|
||||
/* Generate a new serial ID, mark our dependencies with it. */
|
||||
g_mark_serial++;
|
||||
pPlugin->PropogateMarkSerial(g_mark_serial);
|
||||
|
||||
native_count = pContext->GetNativesNum();
|
||||
for (i = 0; i < native_count; i++)
|
||||
{
|
||||
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we're bound, check if there is a replacement available.
|
||||
* If not, this native is totally finalized.
|
||||
*/
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
pEntry = (NativeEntry *)native->user;
|
||||
assert(pEntry != NULL);
|
||||
if (pEntry->replacement.owner == NULL
|
||||
|| (pEntry->replacement.owner != NULL
|
||||
&& pEntry->replacement.func == native->pfn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Otherwise, the native must be in our cache. */
|
||||
else if ((pEntry = FindNative(native->name)) == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bCoreOnly && pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BindNativeToPlugin(pPlugin, native, i, pEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry)
|
||||
{
|
||||
uint32_t i;
|
||||
sp_native_t *native;
|
||||
IPluginContext *pContext;
|
||||
|
||||
pContext = pPlugin->GetBaseContext();
|
||||
|
||||
if (pContext->FindNativeByName(pEntry->name, &i) != SP_ERROR_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (native->status == SP_NATIVE_BOUND)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BindNativeToPlugin(pPlugin, native, i, pEntry);
|
||||
}
|
||||
|
||||
void ShareSystem::BindNativeToPlugin(CPlugin *pPlugin,
|
||||
sp_native_t *native,
|
||||
uint32_t index,
|
||||
NativeEntry *pEntry)
|
||||
{
|
||||
/* Mark as bound... we do the rest next. */
|
||||
native->status = SP_NATIVE_BOUND;
|
||||
native->user = pEntry;
|
||||
|
||||
/* See if a replacement is available. */
|
||||
if (pEntry->replacement.owner != NULL)
|
||||
{
|
||||
/* Perform a replacement bind. */
|
||||
native->pfn = pEntry->replacement.func;
|
||||
pEntry->replacement.owner->AddWeakRef(WeakNative(pPlugin, index, pEntry));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform a normal bind. */
|
||||
native->pfn = pEntry->func;
|
||||
|
||||
/* We don't bother with dependency crap if the owner is Core. */
|
||||
if (pEntry->owner != g_pCoreNatives)
|
||||
{
|
||||
/* The native is optional, this is a special case */
|
||||
if ((native->flags & SP_NTVFLAG_OPTIONAL) == SP_NTVFLAG_OPTIONAL)
|
||||
{
|
||||
pEntry->owner->AddWeakRef(WeakNative(pPlugin, index));
|
||||
}
|
||||
/* Otherwise, we're a strong dependent and not a weak one */
|
||||
else
|
||||
{
|
||||
/* See if this has already been marked as a dependent.
|
||||
* If it has, it means this relationship has already occurred,
|
||||
* and there is no reason to do it again.
|
||||
*/
|
||||
if (pEntry->owner != pPlugin
|
||||
&& pEntry->owner->GetMarkSerial() != g_mark_serial)
|
||||
{
|
||||
/* This has not been marked as a dependency yet */
|
||||
//pPlugin->AddDependency(pEntry->owner);
|
||||
pEntry->owner->AddDependent(pPlugin);
|
||||
pEntry->owner->SetMarkSerial(g_mark_serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
if ((pEntry = FindNative(ntv->name)) == NULL)
|
||||
{
|
||||
pEntry = new NativeEntry;
|
||||
|
||||
pEntry->owner = pOwner;
|
||||
pEntry->name = ntv->name;
|
||||
pEntry->func = ntv->func;
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
pEntry->fake = NULL;
|
||||
|
||||
m_NtvCache.insert(ntv->name, pEntry);
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
if (pEntry->owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pEntry->owner = pOwner;
|
||||
pEntry->func = ntv->func;
|
||||
pEntry->name = ntv->name;
|
||||
pEntry->func = NULL;
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
|
||||
void ShareSystem::ClearNativeFromCache(CNativeOwner *pOwner, const char *name)
|
||||
{
|
||||
NativeEntry *pEntry;
|
||||
|
||||
if ((pEntry = FindNative(name)) == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pEntry->owner != pOwner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pEntry->func = NULL;
|
||||
pEntry->name = NULL;
|
||||
pEntry->owner = NULL;
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
}
|
||||
|
||||
NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
|
||||
{
|
||||
FakeNative *pFake;
|
||||
NativeEntry *pEntry;
|
||||
SPVM_NATIVE_FUNC gate;
|
||||
|
||||
if ((pEntry = FindNative(name)) != NULL && pEntry->owner != NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pFake = new FakeNative;
|
||||
|
||||
if ((gate = g_pVM->CreateFakeNative(func, pFake)) == NULL)
|
||||
{
|
||||
delete pFake;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (pEntry == NULL)
|
||||
{
|
||||
pEntry = new NativeEntry;
|
||||
m_NtvCache.insert(name, pEntry);
|
||||
}
|
||||
|
||||
pFake->call = pFunc;
|
||||
pFake->ctx = pFunc->GetParentContext();
|
||||
strncopy(pFake->name, name, sizeof(pFake->name));
|
||||
|
||||
pEntry->fake = pFake;
|
||||
pEntry->func = gate;
|
||||
pEntry->name = pFake->name;
|
||||
pEntry->owner = g_PluginSys.GetPluginByCtx(pFake->ctx->GetContext());
|
||||
pEntry->replacement.func = NULL;
|
||||
pEntry->replacement.owner = NULL;
|
||||
|
||||
return pEntry;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod
|
||||
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
|
||||
#define _INCLUDE_SOURCEMOD_SHARESYSTEM_H_
|
||||
|
||||
#include <IShareSys.h>
|
||||
#include <IHandleSys.h>
|
||||
#include <sh_list.h>
|
||||
#include <sm_trie_tpl.h>
|
||||
#include "sm_globals.h"
|
||||
#include "sourcemod.h"
|
||||
|
||||
using namespace SourceHook;
|
||||
|
||||
namespace SourceMod
|
||||
{
|
||||
struct IdentityToken_t
|
||||
{
|
||||
Handle_t ident;
|
||||
void *ptr;
|
||||
IdentityType_t type;
|
||||
};
|
||||
};
|
||||
|
||||
struct IfaceInfo
|
||||
{
|
||||
bool operator ==(const IfaceInfo &info)
|
||||
{
|
||||
return (info.iface == iface && info.owner == owner);
|
||||
}
|
||||
SMInterface *iface;
|
||||
IExtension *owner;
|
||||
};
|
||||
|
||||
class CNativeOwner;
|
||||
class CPlugin;
|
||||
struct NativeEntry;
|
||||
|
||||
struct ReplaceNative
|
||||
{
|
||||
CNativeOwner *owner;
|
||||
SPVM_NATIVE_FUNC func;
|
||||
};
|
||||
|
||||
struct FakeNative
|
||||
{
|
||||
char name[64];
|
||||
IPluginContext *ctx;
|
||||
IPluginFunction *call;
|
||||
};
|
||||
|
||||
struct NativeEntry
|
||||
{
|
||||
CNativeOwner *owner;
|
||||
SPVM_NATIVE_FUNC func;
|
||||
const char *name;
|
||||
ReplaceNative replacement;
|
||||
FakeNative *fake;
|
||||
};
|
||||
|
||||
class ShareSystem :
|
||||
public IShareSys,
|
||||
public SMGlobalClass,
|
||||
public IHandleTypeDispatch
|
||||
{
|
||||
friend class CNativeOwner;
|
||||
public:
|
||||
ShareSystem();
|
||||
public: //IShareSys
|
||||
bool AddInterface(IExtension *myself, SMInterface *pIface);
|
||||
bool RequestInterface(const char *iface_name,
|
||||
unsigned int iface_vers,
|
||||
IExtension *myself,
|
||||
SMInterface **pIface);
|
||||
void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
IdentityType_t CreateIdentType(const char *name);
|
||||
IdentityType_t FindIdentType(const char *name);
|
||||
IdentityToken_t *CreateIdentity(IdentityType_t type, void *ptr);
|
||||
void DestroyIdentType(IdentityType_t type);
|
||||
void DestroyIdentity(IdentityToken_t *identity);
|
||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||
void RegisterLibrary(IExtension *myself, const char *name);
|
||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||
public: //SMGlobalClass
|
||||
/* Pre-empt in case anything tries to register idents early */
|
||||
void Initialize();
|
||||
void OnSourceModShutdown();
|
||||
public: //IHandleTypeDispatch
|
||||
void OnHandleDestroy(HandleType_t type, void *object);
|
||||
public:
|
||||
IdentityToken_t *CreateCoreIdentity();
|
||||
void RemoveInterfaces(IExtension *pExtension);
|
||||
public:
|
||||
inline IdentityToken_t *GetIdentRoot()
|
||||
{
|
||||
return &m_IdentRoot;
|
||||
}
|
||||
public:
|
||||
void BindNativesToPlugin(CPlugin *pPlugin, bool bCoreOnly);
|
||||
void BindNativeToPlugin(CPlugin *pPlugin, NativeEntry *pEntry);
|
||||
NativeEntry *AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func);
|
||||
private:
|
||||
NativeEntry *AddNativeToCache(CNativeOwner *pOwner, const sp_nativeinfo_t *ntv);
|
||||
void ClearNativeFromCache(CNativeOwner *pOwner, const char *name);
|
||||
NativeEntry *FindNative(const char *name);
|
||||
void BindNativeToPlugin(CPlugin *pPlugin,
|
||||
sp_native_t *ntv,
|
||||
uint32_t index,
|
||||
NativeEntry *pEntry);
|
||||
private:
|
||||
List<IfaceInfo> m_Interfaces;
|
||||
HandleType_t m_TypeRoot;
|
||||
IdentityToken_t m_IdentRoot;
|
||||
HandleType_t m_IfaceType;
|
||||
IdentityType_t m_CoreType;
|
||||
KTrie<NativeEntry *> m_NtvCache;
|
||||
};
|
||||
|
||||
extern ShareSystem g_ShareSys;
|
||||
|
||||
#endif //_INCLUDE_SOURCEMOD_SHARESYSTEM_H_
|
||||
Reference in New Issue
Block a user