dvander@370: /**
ds@653: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@370: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@370: *
dvander@370: * Version: $Id$
dvander@370: */
dvander@370:
dvander@180: #ifndef _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
dvander@180: #define _INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_
dvander@180:
dvander@180: #include
dvander@180: #include
dvander@180: #include "sm_globals.h"
dvander@180: #include
dvander@180: #include
dvander@211: #include "sourcemod.h"
dvander@180:
dvander@180: using namespace SourceHook;
dvander@180:
dvander@180: typedef List::iterator FuncIter;
dvander@180:
ds@2181: /* :TODO: a global name max define for sourcepawn, should mirror compiler's sNAMEMAX */
dvander@180: #define FORWARDS_NAME_MAX 64
dvander@180:
dvander@183: struct ByrefInfo
dvander@180: {
dvander@183: unsigned int cells;
dvander@183: cell_t *orig_addr;
dvander@183: int flags;
faluco@192: int sz_flags;
dvander@180: };
dvander@180:
dvander@183: struct FwdParamInfo
dvander@183: {
dvander@183: cell_t val;
dvander@183: ByrefInfo byref;
dvander@183: ParamType pushedas;
dvander@183: };
dvander@183:
dvander@2883: class SourceMod::IForwardFilter
dvander@2883: {
dvander@2883: public:
dvander@2883: virtual void Preprocess(IPluginFunction *fun, FwdParamInfo *params)
dvander@2883: {
dvander@2883: }
dvander@2883: };
dvander@2883:
dvander@2890: class FuncIteratorGuard
dvander@2890: {
dvander@2890: bool triggered;
dvander@2890: FuncIteratorGuard **pprev;
dvander@2890: FuncIter *iter;
dvander@2890: FuncIteratorGuard *next;
dvander@2890: public:
dvander@2890: FuncIteratorGuard(FuncIteratorGuard **pprev, FuncIter *iter)
dvander@2890: : triggered(false), pprev(pprev), iter(iter), next(*pprev)
dvander@2890: {
dvander@2890: *pprev = this;
dvander@2890: }
dvander@2890:
dvander@2890: ~FuncIteratorGuard()
dvander@2890: {
dvander@2890: *pprev = next;
dvander@2890: }
dvander@2890:
dvander@2890: inline bool Triggered()
dvander@2890: {
dvander@2890: bool t = triggered;
dvander@2890: triggered = false;
dvander@2890: return t;
dvander@2890: }
dvander@2890:
dvander@2890: /**
dvander@2890: * This should not read from |this| before the NULL check, because FwdSys
dvander@2890: * can call (NULL)->FixIteratorChain().
dvander@2890: */
dvander@2890: void FixIteratorChain(FuncIter &other)
dvander@2890: {
dvander@2890: FuncIteratorGuard *guard = this;
dvander@2890: while (guard != NULL)
dvander@2890: {
dvander@2890: if (*guard->iter == other)
dvander@2890: {
dvander@2890: *(guard->iter) = ++(*(guard->iter));
dvander@2890: guard->triggered = true;
dvander@2890: }
dvander@2890: guard = guard->next;
dvander@2890: }
dvander@2890: }
dvander@2890: };
dvander@2890:
dvander@183: class CForward : public IChangeableForward
dvander@180: {
dvander@180: public: //ICallable
dvander@180: virtual int PushCell(cell_t cell);
ds@585: virtual int PushCellByRef(cell_t *cell, int flags);
dvander@180: virtual int PushFloat(float number);
ds@585: virtual int PushFloatByRef(float *number, int flags);
dvander@589: virtual int PushArray(cell_t *inarray, unsigned int cells, int flags);
dvander@180: virtual int PushString(const char *string);
faluco@192: virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags);
dvander@180: virtual void Cancel();
dvander@180: public: //IForward
dvander@615: virtual const char *GetForwardName();
dvander@615: virtual unsigned int GetFunctionCount();
dvander@615: virtual ExecType GetExecType();
dvander@180: virtual int Execute(cell_t *result, IForwardFilter *filter);
dvander@180: public: //IChangeableForward
dvander@180: virtual bool RemoveFunction(IPluginFunction *func);
dvander@180: virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin);
dvander@180: virtual bool AddFunction(IPluginFunction *func);
dvander@327: virtual bool AddFunction(IPluginContext *ctx, funcid_t index);
ds@621: virtual bool RemoveFunction(IPluginContext *ctx, funcid_t index);
dvander@180: public:
dvander@180: static CForward *CreateForward(const char *name,
dvander@180: ExecType et,
dvander@180: unsigned int num_params,
ds@559: const ParamType *types,
dvander@180: va_list ap);
dvander@180: private:
dvander@180: void _Int_PushArray(cell_t *inarray, unsigned int cells, int flags);
faluco@192: void _Int_PushString(cell_t *inarray, unsigned int cells, int sz_flags, int cp_flags);
dvander@180: inline int SetError(int err)
dvander@180: {
dvander@180: m_errstate = err;
dvander@180: return err;
dvander@180: }
dvander@180: protected:
dvander@180: /* :TODO: I want a caching list type here.
dvander@180: * Destroying these things and using new/delete for their members feels bad.
dvander@180: */
dvander@464: mutable List m_functions;
dvander@527: mutable List m_paused;
dvander@2890: FuncIteratorGuard *m_IterGuard;
dvander@180:
dvander@180: /* Type and name information */
dvander@183: FwdParamInfo m_params[SP_MAX_EXEC_PARAMS];
dvander@180: ParamType m_types[SP_MAX_EXEC_PARAMS];
dvander@180: char m_name[FORWARDS_NAME_MAX+1];
dvander@180: unsigned int m_numparams;
dvander@183: unsigned int m_varargs;
dvander@180: ExecType m_ExecType;
dvander@180:
dvander@180: /* State information */
dvander@180: unsigned int m_curparam;
dvander@180: int m_errstate;
dvander@180: };
dvander@180:
dvander@211: class CForwardManager :
dvander@211: public IForwardManager,
dvander@211: public IPluginsListener,
dvander@211: public SMGlobalClass
dvander@186: {
dvander@186: friend class CForward;
faluco@641: public:
faluco@641: ~CForwardManager();
dvander@211: public: //IForwardManager
faluco@430: IForward *CreateForward(const char *name,
dvander@186: ExecType et,
dvander@186: unsigned int num_params,
ds@559: const ParamType *types,
dvander@186: ...);
faluco@430: IChangeableForward *CreateForwardEx(const char *name,
dvander@186: ExecType et,
dvander@186: int num_params,
ds@559: const ParamType *types,
dvander@186: ...);
faluco@430: IForward *FindForward(const char *name, IChangeableForward **ifchng);
faluco@430: void ReleaseForward(IForward *forward);
dvander@211: public: //IPluginsListener
faluco@430: void OnPluginLoaded(IPlugin *plugin);
faluco@430: void OnPluginUnloaded(IPlugin *plugin);
faluco@430: void OnPluginPauseChange(IPlugin *plugin, bool paused);
dvander@211: public: //SMGlobalClass
faluco@430: void OnSourceModAllInitialized();
dvander@186: protected:
dvander@186: CForward *ForwardMake();
dvander@186: void ForwardFree(CForward *fwd);
dvander@186: private:
dvander@186: CStack m_FreeForwards;
dvander@186: List m_managed;
dvander@186: List m_unmanaged;
dvander@186: };
dvander@186:
dvander@186: extern CForwardManager g_Forwards;
dvander@186:
dvander@180: #endif //_INCLUDE_SOURCEMOD_FORWARDSYSTEM_H_