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_